日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Slice 擴(kuò)容后容量及內(nèi)存如何計(jì)算?

1. 擴(kuò)容后預(yù)估容量

假設(shè)現(xiàn)在有一個(gè)長(zhǎng)度為 2 的切片,對(duì)其進(jìn)行擴(kuò)容,增加三個(gè)元素

 
 
 
  1. sli := []int{1,2} 
  2. sli = append(sli, 3, 4, 5) 

對(duì)于擴(kuò)容后的切片,長(zhǎng)度為 5,這一點(diǎn)沒有任何爭(zhēng)議。

但容量呢?難道也是 5?

經(jīng)過(guò)運(yùn)行驗(yàn)證,實(shí)際的容量為 6 。

什么情況?這 6 是如何計(jì)算出來(lái)的呢?

這就不得不去 Go 源代碼中一探究竟,在 runtime/slice.go 關(guān)于 slice 擴(kuò)容增長(zhǎng)的代碼如下:

 
 
 
  1. newcap := old.cap 
  2. if newcap+newcap < cap { 
  3.     newcap = cap 
  4. } else { 
  5.     for { 
  6.         if old.len < 1024 { 
  7.             newcap += newcap 
  8.         } else { 
  9.             newcap += newcap / 4 
  10.         } 
  11.         if newcap >= cap { 
  12.             break 
  13.         } 
  14.     } 

對(duì)于這段代碼,只要理解前兩行,其他的就不攻自破了

  • 第一行的 old.cap:擴(kuò)容前的容量,對(duì)于此例,就是 2
  • 第二行的 cap:擴(kuò)容前容量加上擴(kuò)容的元素?cái)?shù)量,對(duì)于此例,就是 2+3

整段代碼的核心就是要計(jì)算出擴(kuò)容后的預(yù)估容量,也就是 newcap,計(jì)算的具體邏輯是:

  1. 若 old.cap * 2 小于 cap,那 newcap 就取大的 cap
  2. 若 old.cap * 2 大于 cap,并且old.cap 小于 1024,那 newcap 還是取大,也即 newcap = old.cap * 2
  3. 若 old.cap * 2 大于 cap,但是old.cap 大于 1024,那兩倍冗余可能就有點(diǎn)大了,系數(shù)換成 1.25,也即 newcap = old.cap * 2

但 newcap 只是預(yù)估容量,并不是最終的容量,要計(jì)算最終的容量,還需要參考另一個(gè)維度,也就是內(nèi)存分配。

 2. 內(nèi)存的分配規(guī)律

舉個(gè)現(xiàn)實(shí)中的例子來(lái)說(shuō)

你家里有五個(gè)人,每個(gè)人都想吃綠豆糕,因此你的需求就是 5,對(duì)應(yīng)上例中的 cap ,于是你就到超市里去買。

但超市并不是你家開的,綠豆糕都是整盒整盒的賣,沒有賣散的,每盒的數(shù)量是 6 個(gè),因此你最少買 6 個(gè)。

每次購(gòu)買的最少數(shù)量,就可以類比做 Go 的內(nèi)存分配規(guī)律。

只有了解了 Go 的內(nèi)存分配規(guī)律,我們才能準(zhǔn)確的計(jì)算出我們最少得買多少的綠豆糕(得申請(qǐng)多少的內(nèi)存,分配多少的容量)。

關(guān)于內(nèi)存管理模塊的代碼,在 runtime/sizeclasses.go

 
 
 
  1. // class  bytes/obj  bytes/span  objects  tail waste  max waste 
  2. //     1          8        8192     1024           0     87.50% 
  3. //     2         16        8192      512           0     43.75% 
  4. //     3         32        8192      256           0     46.88% 
  5. //     4         48        8192      170          32     31.52% 
  6. ... 
  7. //    17        256        8192       32           0      5.86% 
  8. //    18        288        8192       28         128     12.16% 
  9. //    19        320        8192       25         192     11.80% 
  10. //    20        352        8192       23          96      9.88% 
  11. //    21        384        8192       21         128      9.51% 
  12. //    22        416        8192       19         288     10.71% 
  13. //    23        448        8192       18         128      8.37% 
  14. //    24        480        8192       17          32      6.82% 
  15. //    25        512        8192       16           0      6.05% 
  16. ... 
  17. //    66      32768       32768        1           0     12.50% 

從上面這個(gè)表格中,可以總結(jié)出一些規(guī)律。

  • 在小于16字節(jié)時(shí),每次以8個(gè)字節(jié)增加
  • 當(dāng)大于16小于2^8時(shí),每次以16字節(jié)增加
  • 當(dāng)大于2^8小于2^9時(shí)以32字節(jié)增加
  • 依此規(guī)律…

3. 匹配到合適的內(nèi)存

第一節(jié)中我們例子中,主人公是一個(gè)元素類型為 int 的切片,每個(gè) int 占用為 8 個(gè)字節(jié),由于我們計(jì)算出的 newcap 為 5,因此新的切片,最少最少要占用 5*8 = 40 個(gè)字節(jié)。

再到第二節(jié)中的表格中查看,發(fā)現(xiàn)離 40 byte 最接近的是 32 和 48 兩個(gè)檔位。

如果是 32 byte,就是不夠用了,

因此 只能選擇 48 這個(gè)檔位去分配內(nèi)存。

有了實(shí)際分配的內(nèi)存,再反回去計(jì)算容量,就是擴(kuò)容后真實(shí)的切片容量,也就是 48/8 = 6

是不是很簡(jiǎn)單呢?


當(dāng)前標(biāo)題:Slice 擴(kuò)容后容量及內(nèi)存如何計(jì)算?
網(wǎng)頁(yè)地址:http://www.dlmjj.cn/article/dpjgocc.html