题目序号:(850)
题目来源:小米
题目频次:1
答案1:(自由)
扩容是为切片分配新的内存空间并复制原切片中元素的过程。在 go 语言的切片中,扩容的过程是:估计大致容量 -> 确定容量 -> 覆盖原切片 -> 完成扩容。
先确定新的切片大致容量而分配内存空间,根据该切片当前容量选择不同的策略:
- 如果期望容量大于当前容量的两倍,就会使用期望容量
- 如果当前切片的长度小于 1024,容量就会翻倍
- 如果当前切片的长达大于 1024,每次扩容 25% 的容量,直到新容量大于期望容量。
估计大致容量后,开始确定容量,根据切片中的元素大小对齐内存情况来确定容量。当元素所占字节大小为 1、2、8 的倍数时,会通过 runtime.roundupsize 函数来确定待申请的内存,该函数会从一个数组中获取整数,使用这个数组中的元素可以提高内存分配效率并减少碎片,这个数组叫做 NumSizeClasses 。
扩展:切片的扩容与追加元素息息相关。是否扩容是由中间代码生成阶段的 cmd/compile/internal/gc.state.append 方法的返回值决定的,这个方法的返回值是一个新切片,如果这个新切片不赋值回原变量,那么 go 会获取这个切片的数组指针、大小和容量,判断追加元素后切片大小是否大于容量,如果大于,会调用 runtime.growslice 对切片进行扩容并将新元素依次加入新切片。如果方法返回的新切片,赋值回原变量,那么会以另外一种方式判断是否需要扩容,当然,扩容还是通过 runtime.growslice。不过它们的区别在新切片是否会赋值回原变量,如果覆盖原变量,就无须担心切片发生复制而影响性能。
本文来自投稿,不代表本站立场,如若转载,请注明出处: