当前位置: 首页 > 科技观察

扩容后Slice的容量和内存如何计算?

时间:2023-03-17 00:31:22 科技观察

1。扩容后预估容量假设有一个长度为2的slice,对其进行扩容,添加三个元素sli:=[]int{1,2}sli=append(sli,3,4,5)为扩容后的slice,长度为5,没有争议。但是容量呢?也是5吗?运行验证后,实际容量为6,请问是什么情况?这个6是怎么计算的?你必须去Go源代码才能找到答案。runtime/slice.go中slice扩容增长的代码如下:newcap:=old.capifnewcap+newcap=cap{break}}这段代码只要看懂前两行,其他的就不会break因为第一行的old.cap是break的:扩容前的容量,对于这个例子,就是2第二行的cap:扩容前的容量加上扩容元素的个数,对于这个例子,就是整个代码的2+3核心是计算扩容后的预估容量,即是,newcap。具体的计算逻辑是:如果old.cap*2小于cap,那么newcap取一个更大的cap。如果old.cap*2大于cap,则为old。如果cap小于1024,那么newcap还是更大,即newcap=old.cap*2如果old.cap*2大于cap,但是old.cap大于1024,那么双冗余可能是一个有点大,系数改为1.25,即newcap=old.cap*2但newcap只是估计容量,不是最终容量。计算最终容量还需要参考另一个维度,即内存分配。2.内存分配规律举个现实生活中的例子。你家有五个人,每个人都想吃绿豆糕,所以你的需求是5,对应上面例子中的cap,所以你去超市买。但是超市不是你家开的。绿豆糕是整箱销售,不散装销售。每箱的数量是6个,所以至少要买6个。每次的最小购买数量可以类比Go的内存分配规则。只有了解了Go的内存分配规则,才能准确计算出我们最少需要购买的绿豆糕数量(申请多少内存,分配多少容量)。关于内存管理模块的代码,在runtime/sizeclasses.go//classbytes/objbytes/spanobjectstailwastemaxwaste//1881921024087.50%//2168192512043.75%//3328192256046.88%//44881921703231.52%...//1725681923205.86%//1828881922812812.16%//1932081922519211.80%//20352819223969.88%//213848192211289.51%//224168192192810.71%//234488192181288.37%//24480819217326.82%//2551281921606.05%...//大于16小于2^8时,每次增加16字节;当大于2^8小于2^9时,按照这个规则增加32个字节...3.匹配到合适的内存在我们第一节的例子中,主角是一个元素类型为int的slice,每个int占用8个字节。由于我们计算出来的newcap是5,新的slice,至少需要5*8=40字节。翻到第二节的表格,发现最接近40字节的是32和48档。如果是32字节就不够了,只能选择48来分配内存。有了实际分配的内存,再回去算一下容量,就是扩容后真正的分片容量,也就是48/8=6,是不是很简单?