為什么 Go 關(guān)心 unsafe.Pointer 和 uintptr 之間的差別
點(diǎn)擊上方藍(lán)色“Go語言中文網(wǎng)”關(guān)注我們,領(lǐng)全套Go資料,每天學(xué)習(xí)?Go?語言
Go 有兩樣?xùn)|西或多或少是無類型指針的表示:uintptr 和 unsafe.Pointer (和外表相反,它們是內(nèi)置類型)。從表面上看這有點(diǎn)奇怪,因?yàn)?unsafe.Pointer 和 uintptr 可以彼此來回轉(zhuǎn)換。為什么不只有一種指針表現(xiàn)形式?兩者之間有什么區(qū)別?
表面的區(qū)別是可以對 uintptr 進(jìn)行算數(shù)運(yùn)算但不能對 unsafe.Pointer(或任何其他 Go 指針)進(jìn)行運(yùn)算。unsafe 包的文檔指出了重要的區(qū)別:
uintptr 是整數(shù),不是引用。將 Pointer 轉(zhuǎn)換為 uintptr 會創(chuàng)建一個沒有指針語義的整數(shù)值。即使 uintptr 持有某個對象的地址,如果對象移動,垃圾收集器并不會更新 uintptr 的值,uintptr 也無法阻止該對象被回收。
盡管 unsafe.Pointer 是通用指針,但 Go 垃圾收集器知道它們指向 Go 對象;換句話說,它們是真正的 Go 指針。通過內(nèi)部魔法,垃圾收集器可以并且將使用它們來防止活動對象被回收并發(fā)現(xiàn)更多活動對象(如果unsafe.Pointer指向的對象自身持有指針)。因此,對 unsafe.Pointer 的合法操作上的許多限制歸結(jié)為“在任何時候,它們都必須指向真正的 Go 對象”。如果創(chuàng)建的 unsafe.Pointer 并不符合,即使很短的時間,Go 垃圾收集器也可能會在該時刻掃描,然后由于發(fā)現(xiàn)了無效的 Go 指針而崩潰。
相比之下,uintptr 只是一個數(shù)字。這種特殊的垃圾收集魔法機(jī)制并不適用于 uintptr 所“引用”的對象,因?yàn)樗鼉H僅是一個數(shù)字,一個 uintptr 不會引用任何東西。反過來,這導(dǎo)致在將 unsafe.Pointer 轉(zhuǎn)換為 uintptr,對其進(jìn)行操作然后再將其轉(zhuǎn)回的各種方式上存在許多微妙的限制?;疽笫且赃@種方式進(jìn)行操作,使編譯器和運(yùn)行時可以屏蔽不安全的指針的臨時非指針性,使其免受垃圾收集器的干擾,因此這種臨時轉(zhuǎn)換對于垃圾收集將是原子的。
(我想,我在文章將內(nèi)存塊復(fù)制到 Go 結(jié)構(gòu)中[1]里對 unsafe.Pointer 的使用是安全的,但我承認(rèn)我現(xiàn)在不確定。我相信 cgo 會有一些不可思議的機(jī)制,因?yàn)樗梢园踩刂圃斐霾话踩闹羔槪@些指針指向 C 內(nèi)存而不是 Go 內(nèi)存。)
PS:從 Go 1.8 開始,即使當(dāng)時沒有運(yùn)行垃圾回收,所有 Go 指針必須始終有效(我相信也包括 unsafe.Pointer)。如果您在變量或字段中存儲了無效的指針,則僅通過將字段更新為包括 nil 在內(nèi)的完全有效的值即可使代碼崩潰。例如,請參閱這個有教育意義的 Go bug report[2]。
(我本想嘗試講一下內(nèi)部魔法,它允許垃圾收集器處理未類型化的 unsafe.Pointer 指針,但我認(rèn)為對其了解不足,甚至無法說出它使用的是哪種魔法。)
via: https://utcc.utoronto.ca/~cks/space/blog/programming/GoUintptrVsUnsafePointer
作者:ChrisSiebenmann[3]譯者:dust347[4]校對:polaris1119[5]
本文由 GCTT[6] 原創(chuàng)編譯,Go 中文網(wǎng)[7] 榮譽(yù)推出
參考資料
[1]將內(nèi)存塊復(fù)制到 Go 結(jié)構(gòu)中: https://utcc.utoronto.ca/~cks/space/blog/programming/GoMemoryToStructures
[2]這個有教育意義的 Go bug report: https://github.com/golang/go/issues/19135
[3]ChrisSiebenmann: https://utcc.utoronto.ca/~cks/space/People/ChrisSiebenmann
[4]dust347: https://github.com/dust347
[5]polaris1119: https://github.com/polaris1119
[6]GCTT: https://github.com/studygolang/GCTT
[7]Go 中文網(wǎng): https://studygolang.com/
推薦閱讀
站長 polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場和創(chuàng)業(yè)經(jīng)驗(yàn)
Go語言中文網(wǎng)
每天為你
分享 Go 知識
Go愛好者值得關(guān)注
