<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go 切片的一種有趣內(nèi)存泄漏方式

          共 2537字,需瀏覽 6分鐘

           ·

          2020-10-14 09:03

          點(diǎn)擊上方藍(lán)色“Go語(yǔ)言中文網(wǎng)”關(guān)注,回復(fù)「電子書(shū)」領(lǐng)全套Go資料

          今天我在看 Prashant Varanasi 的 Go 發(fā)布會(huì)演講:使用火焰圖進(jìn)行生產(chǎn)分析[1](Analyzing production using Flamegraphs),在演講開(kāi)始的第 28 分鐘他提到了一種涉及切片的有趣且棘手的內(nèi)存泄漏。為了自我提升,我將在這里寫(xiě)一下該內(nèi)存泄漏的一種形式,并說(shuō)明它是如何發(fā)生的。

          首先,對(duì)于像 Go 這樣的垃圾收集語(yǔ)言來(lái)說(shuō),內(nèi)存泄漏是保留了對(duì)對(duì)象的非預(yù)期引用所造成的。垃圾收集器會(huì)幫你尋找并釋放對(duì)象,但前提是它們事實(shí)上并沒(méi)有被使用。如果你保留了對(duì)它們的引用,它們會(huì)留下來(lái)。有時(shí)最終結(jié)果很簡(jiǎn)單(也行你故意保留一個(gè)較小的結(jié)構(gòu),但沒(méi)意識(shí)到它引用了一個(gè)較大的結(jié)構(gòu)),但有時(shí)候這種保留隱藏在某些東西的運(yùn)行時(shí)實(shí)現(xiàn)里。這改變了我們對(duì)切片的看法。

          簡(jiǎn)化之后,Prashant 處理的代碼在一個(gè)切片中維護(hù)了當(dāng)前在使用的元素的集合。當(dāng)一個(gè)元素不再被使用時(shí),它被轉(zhuǎn)移到了切片的末尾,然后切片被截?cái)喽s小(保持不變的是切片只保留使用的元素)。然而,縮小切片并不會(huì)縮小其依賴的數(shù)組,用 Go 的術(shù)語(yǔ)來(lái)說(shuō),減小了切片的長(zhǎng)度但是并沒(méi)有減少容量。由于底層依賴的數(shù)組沒(méi)有變動(dòng),而該數(shù)組保留了一個(gè)理論上已經(jīng)被丟棄了的元素的引用,以及該元素所引用的所有其他對(duì)象。即使是代碼不可見(jiàn)的引用被保留,Go 垃圾收集器仍然會(huì)將該元素看做是還在使用中。代碼認(rèn)為以及被丟棄了的元素實(shí)際上并沒(méi)有被釋放,這就造成了內(nèi)存泄漏。

          現(xiàn)在,我查看了 Go 運(yùn)行時(shí)和編譯器代碼,并對(duì)該問(wèn)題進(jìn)行了一些思考,我清楚地意識(shí)到了這是任何切片截?cái)嗟耐ㄓ脝?wèn)題。Go 絕不會(huì)嘗試縮小切片的底層數(shù)組,而且通常來(lái)說(shuō)這樣做是不可能的,因?yàn)?span style="font-weight: bold;color: #ff3502;">一個(gè)底層數(shù)組可能被多個(gè)切片[2]或其他引用所共享。這顯然會(huì)嚴(yán)重影響指向包含指針的對(duì)象的切片,但對(duì)于指向普通的舊數(shù)據(jù)的切片也可能很重要,尤其是當(dāng)它們比較大的時(shí)候(比如你有一個(gè) Point 的切片,每個(gè) Point 有三個(gè)浮點(diǎn)數(shù))。

          對(duì)于包含指針或者包含持有著指針的結(jié)構(gòu)的切片來(lái)說(shuō),明顯的修復(fù)方式(這是Uber 代碼中采用的修復(fù)方式[3])是在截?cái)嗲衅皩⒛┪驳闹羔樦脼榭铡_@樣保留了完整的底層數(shù)組,但拋棄了對(duì)其他內(nèi)存的引用,而這些其他的內(nèi)存是真正內(nèi)存泄漏的地方。

          對(duì)于實(shí)際的底層數(shù)組可能會(huì)有大量?jī)?nèi)存消耗的切片來(lái)說(shuō),我想到可能有兩種做法,一種特殊,一種通用。特殊的一種是檢查代碼中“大小截?cái)酁榱恪钡那闆r,并專(zhuān)門(mén)將切片本身置為空,而不是僅僅使用標(biāo)準(zhǔn)的切片截?cái)喙δ軄?lái)截?cái)唷Mㄓ玫淖龇ㄊ敲鞔_地強(qiáng)制使用切片拷貝而不是僅僅截?cái)啵ň腿?span style="font-weight: bold;color: #ff3502;">我對(duì)切片可變性的評(píng)論[4]提到的)。強(qiáng)制使用拷貝所帶來(lái)的缺點(diǎn)是,某些時(shí)候可能會(huì)帶來(lái)更大的開(kāi)銷(xiāo)。你可以通過(guò)僅在切片的容量遠(yuǎn)遠(yuǎn)超出新切片的長(zhǎng)度的時(shí)候才強(qiáng)制使用拷貝的方式來(lái)進(jìn)行優(yōu)化。

          補(bǔ)充:(對(duì)垃圾收集而言)三索引的切片截?cái)嗍俏kU(xiǎn)的

          Go 切片表達(dá)式[5]允許在起終點(diǎn)之外,使用很少使用的第三個(gè)索引來(lái)設(shè)置新切片的容量。你也許會(huì)想到采用這種形式限制切片,來(lái)作為解決垃圾收集問(wèn)題的辦法:

          slc?=?slc[:newlen:newlen]

          不幸的是,這樣并不會(huì)達(dá)到你想要的效果,而且會(huì)適得其反。設(shè)置新切片的容量完全不會(huì)改變底層的依賴數(shù)組,也不會(huì)讓 Go 分配一個(gè)新的內(nèi)存,但這卻意味著你無(wú)法獲取數(shù)組大小的信息(否則可以通過(guò)切片的容量來(lái)得到它)。這樣造成的唯一影響是強(qiáng)制隨后的 append() 重新分配新的底層數(shù)組。


          via: https://utcc.utoronto.ca/~cks/space/blog/programming/GoSlicesMemoryLeak

          作者:ChrisSiebenmann[6]譯者:dust347[7]校對(duì):polaris1119[8]

          本文由 GCTT[9] 原創(chuàng)編譯,Go 中文網(wǎng)[10] 榮譽(yù)推出

          參考資料

          [1]

          使用火焰圖進(jìn)行生產(chǎn)分析: https://www.youtube.com/watch?v=aAhNDgEZj_U

          [2]

          一個(gè)底層數(shù)組可能被多個(gè)切片: https://utcc.utoronto.ca/~cks/space/blog/programming/GoSliceMutability

          [3]

          Uber 代碼中采用的修復(fù)方式: https://github.com/uber/tchannel-go/commit/63a486b96821eaa6fb2299663dda5c529cc04666#diff-32e1ab53c69bf3272bd9e4b51b9bb105

          [4]

          我對(duì)切片可變性的評(píng)論: https://utcc.utoronto.ca/~cks/space/blog/programming/GoSliceMutability

          [5]

          Go 切片表達(dá)式: https://golang.org/ref/spec#Slice_expressions

          [6]

          ChrisSiebenmann: https://utcc.utoronto.ca/~cks/space/People/ChrisSiebenmann

          [7]

          dust347: https://github.com/dust347

          [8]

          polaris1119: https://github.com/polaris1119

          [9]

          GCTT: https://github.com/studygolang/GCTT

          [10]

          Go 中文網(wǎng): https://studygolang.com/



          推薦閱讀


          福利

          我為大家整理了一份從入門(mén)到進(jìn)階的Go學(xué)習(xí)資料禮包(下圖只是部分),同時(shí)還包含學(xué)習(xí)建議:入門(mén)看什么,進(jìn)階看什么。

          關(guān)注公眾號(hào) 「polarisxu」,回復(fù) ebook 獲取;還可以回復(fù)「進(jìn)群」,和數(shù)萬(wàn) Gopher 交流學(xué)習(xí)。

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人影音百度 | 一区二区三区精品视频在线观看 | 国产亚洲欧美日韩高清 | 亚洲AV色香蕉一区二区三区 | 操鼻素材大全在线观看 |