“This is the 25th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

preface

The previous article briefly introduced slice’s features, and this article takes a closer look at Slice.

Initialize the

As with other data structures in the GO language, slices are allocated to the heap when they are initialized in size larger than 64KB. If the size of the slice is less than 64KB, the slice is allocated to the stack. In addition, the SmallFrames parameter can be specified at compile time, which is a Boolean value that specifies whether it is allocated to the stack when the volume is low.

capacity

In growslice, this function is used to pass in the element type, the old slice, the required new size, apply for a new slice in memory, and copy the old slice into it.

One interesting thing about this code is that the designers even considered extending a null pointer in advance

if et.size == 0 {
   return slice{unsafe.Pointer(&zerobase), old.len.cap}}Copy the code

Next comes the calculation of capacity

if cap > doublecap {
   newcap = cap
} else {
   if old.cap < 1024 {
      newcap = doublecap
   } else {
      for 0 < newcap && newcap < cap {
         newcap += newcap / 4
      }
      // Set newcap to the requested cap when
      // the newcap calculation overflowed.
      if newcap <= 0 {
         newcap = cap}}}Copy the code

Three concepts need to be distinguished: old capacity, required capacity, and new capacity.

  • If the required capacity is greater than twice the old capacity, set to the required capacity,
  • If the old capacity is less than 1024, set it to twice the old capacity (which is quite similar to Java to be honest)
  • The loop keeps increasing the old capacity by 25% until it exceeds the required capacity
    • If it overflows, forget it.

Even if the capacity is determined, go language will adjust the size of the slice due to reasons such as memory alignment, so it will generally be greater than or equal to the calculated capacity * element size.

When the slice type is not a pointer, the memory behind the new address is cleared, and the old slice is moved to the new memory using memmove.

var p unsafe.Pointer
if et.ptrdata == 0 {
   p = mallocgc(capmem, nil.false)
   memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
}else{}
memmove(p, old.array, lenmem)
Copy the code