1 回答
TA貢獻1847條經驗 獲得超11個贊
當運行時檢測到Go代碼無法到達再次引用該變量的點時,該變量將變得不可訪問。
在您發布的示例中, asyscall.Open()用于打開文件。返回的文件描述符(只是一個int值)被“包裝”在struct. 然后一個終結器附加到這個結構值上,關閉文件描述符?,F在,當這個結構值變得不可訪問時,它的終結器可能隨時運行,并且文件描述符的關閉/失效/重用可能會導致Read()系統調用執行時出現意外行為或錯誤。
p在Go代碼中這個結構值的最后一次使用是什么時候syscall.Read()被調用(并且文件描述符p.d被傳遞給它)。系統調用的實現將在啟動后使用該文件描述符syscall.Read(),它可能會一直這樣做直到syscall.Read()返回。但是文件描述符的這種使用是“獨立”于 Go 代碼的。
所以p在執行系統調用期間不使用結構值,系統調用會阻塞 Go 代碼,直到它返回。這意味著允許 Go 運行時p在執行期間Read()(Read()返回之前)或什至在其實際執行開始之前標記為不可訪問(因為p僅用于為 call 提供參數Read()。
因此調用runtime.KeepAlive(): 因為這個調用在之后并且syscall.Read()它引用了變量p,所以 Go 運行時不允許在返回p之前標記 unreachable Read(),因為這是在Read()調用之后。
請注意,您可以使用其他構造來“保持p活力”,例如_ = p或返回它。runtime.KeepAlive()在后臺沒有做任何神奇的事情,它的實現是:
func KeepAlive(interface{}) {}runtime.KeepAlive() 確實提供了更好的選擇,因為:
它清楚地記錄了我們想要保持
p活動狀態(以防止運行Finalizers)。使用其他結構,例如
_ = p可能會被未來的編譯器“優化”出來,但不會被runtime.KeepAlive()調用。
- 1 回答
- 0 關注
- 192 瀏覽
添加回答
舉報
