Go 開(kāi)發(fā)者不需要寫代碼來(lái)釋放程序中不再使用的變量和結(jié)構(gòu)占用的內(nèi)存,在 Go 運(yùn)行時(shí)中有一個(gè)獨(dú)立的進(jìn)程,即垃圾收集器(GC),會(huì)處理這些事情,它搜索不再使用的變量然后釋放它們的內(nèi)存??梢酝ㄟ^(guò) runtime
包訪問(wèn) GC 進(jìn)程。
通過(guò)調(diào)用 runtime.GC()
函數(shù)可以顯式的觸發(fā) GC,但這只在某些罕見(jiàn)的場(chǎng)景下才有用,比如當(dāng)內(nèi)存資源不足時(shí)調(diào)用 runtime.GC()
,它會(huì)在此函數(shù)執(zhí)行的點(diǎn)上立即釋放一大片內(nèi)存,此時(shí)程序可能會(huì)有短時(shí)的性能下降(因?yàn)?GC
進(jìn)程在執(zhí)行)。
如果想知道當(dāng)前的內(nèi)存狀態(tài),可以使用:
// fmt.Printf("%d\n", runtime.MemStats.Alloc/1024)
// 此處代碼在 Go 1.5.1下不再有效,更正為
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("%d Kb\n", m.Alloc / 1024)
上面的程序會(huì)給出已分配內(nèi)存的總量,單位是 Kb。進(jìn)一步的測(cè)量參考 文檔頁(yè)面。
如果需要在一個(gè)對(duì)象 obj 被從內(nèi)存移除前執(zhí)行一些特殊操作,比如寫到日志文件中,可以通過(guò)如下方式調(diào)用函數(shù)來(lái)實(shí)現(xiàn):
runtime.SetFinalizer(obj, func(obj *typeObj))
func(obj *typeObj)
需要一個(gè) typeObj
類型的指針參數(shù) obj
,特殊操作會(huì)在它上面執(zhí)行。func
也可以是一個(gè)匿名函數(shù)。
在對(duì)象被 GC 進(jìn)程選中并從內(nèi)存中移除以前,SetFinalizer
都不會(huì)執(zhí)行,即使程序正常結(jié)束或者發(fā)生錯(cuò)誤。
練習(xí) 10.17
從練習(xí) 10.16 開(kāi)始(它基于結(jié)構(gòu)體實(shí)現(xiàn)了一個(gè)棧結(jié)構(gòu)),為棧的實(shí)現(xiàn)(stack_struct.go)創(chuàng)建一個(gè)單獨(dú)的包 stack
,并從 main
包 main.stack.go
中調(diào)用它。