Go 1.8: Argument Liveness

問題描述

下面是Go 1.8 release notes中對該問題描述

The garbage collector no longer considers arguments live throughout the entirety of a function. For more information, and for how to force a variable to remain live, see the runtime.KeepAlive
function added in Go 1.7.

什么意思呢?就是說從1.8版本開始,go的GC不再管你變量在函數(shù)中的作用域了,只要GC發(fā)現(xiàn)后面這個變量沒有再被使用了,就回收。乍一看好像很有問題,仔細想似乎又沒什么問題。

緊接著官方對這個問題進行了一次update:

Updating: Code that sets a finalizer on an allocated object may need to add calls to runtime.KeepAlive
in functions or methods using that object. Read the KeepAlive
documentation
and its example for more details.

Update的內(nèi)容對該問題的影響進行了具體說明,就是當用戶自己對一個對象設置了finalizer時,需要根據(jù)自己的需要來決定在哪個地方調(diào)用KeepAlive,以保證在此之前,GC不會回收該對象。就是說,雖然用戶設置了finalizer,但finalizer的觸發(fā)是由GC來控制的。新版本的GC是并行執(zhí)行的,且不關心變量在函數(shù)中的作用域了,因此很可能在你不希望他釋放的時候,GC把對象給釋放掉了。

解決方案

下面是官方給的一段典型的示例代碼:


type File struct { d int }
d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0)
// ... do something if err != nil ...
p := &Fileu0z1t8os
runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) })
var buf [10]byte
n, err := syscall.Read(p.d, buf[:])

解釋一下問題出在哪里:變量p創(chuàng)建之后,用戶給它設置了
finalizer。然后開始調(diào)用syscall.Read,注意Read傳的參數(shù)是p.d,Go中傳參都是復制的,也就是Read里面使用的變量跟變量p沒有半毛錢關系。也就是Read函數(shù)調(diào)用之后,結(jié)束之前,變量p就失去了存在的意義,GC會忠實的履行自己的職責,將p給回收,此時觸發(fā)了用戶自己設置的finalizer,將文件描述符給關閉了。但這個時候,Read操作可能還在通過該文件描述符訪問文件,這就是問題所在。
解決此問題的方法:


type File struct { d int }
d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0)
// ... do something if err != nil ...
p := &Fileu0z1t8os
runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) })
var buf [10]byte
n, err := syscall.Read(p.d, buf[:])
// Ensure p is not finalized until Read returns.
runtime.KeepAlive(p)
// No more uses of p after this point.

就是在Read函數(shù)調(diào)用之后,對對象p手動調(diào)用一次KeepAlive,KeepAlive是個空函數(shù),只是欺騙一下GC,變量p到這里還有被使用,在此之前不要回收。這就確保了Read返回前,對象p不會被回收。當然KeepAlive之后,p就會被GC回收。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,725評論 25 709
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,241評論 0 62
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內(nèi)部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,623評論 18 399
  • 在生活中,我們總能聽到,XXX是人生贏家,或許他事業(yè)有成、腰纏萬貫;或許她相夫教子、家庭和睦。但我總覺得,人生贏家...
    tracyduan閱讀 616評論 0 0

友情鏈接更多精彩內(nèi)容