我有一个包含许多对象的数组。当我将数组设置为nil时,gc会收集数组所拥有的所有对象吗?
package main
import (
"time"
"runtime"
)
type B struct {
bb []int
}
func NewB() *B {
return new(B)
}
func main() {
var bs = make([]*B, 10)
for i:=0; i<10; i++ {
bs[i] = NewB()
bs[i].bb = make([]int, 1000000)
}
time.Sleep(time.Second)
println("begin gc")
//for i:=0; i<10; i++ {
// bs[i] = nil
//}
bs = nil
runtime.GC()
time.Sleep(time.Second*2)
runtime.GC()
time.Sleep(time.Second*2)
}
首先,我设置bs = nil
,所有两个gc信息显示76->76->76 MB
,这意味着gc不会释放内存。
然后,我在斜杠语句中添加for循环代码,第一个gc信息显示76->76->0 MB
,第二个gc信息显示0->0->0 MB
。
所以我很困惑,当我设置bs = nil
时,没有指针引用所有对象,为什么gc不释放对象?是否所有对象都明确设置为nil?
答案 0 :(得分:4)
如果你在启用转义分析的情况下进行编译,你会看到bs没有转义,所以在堆栈上分配,而不是堆
go run -gcflags '-m -l' gc.go
# command-line-arguments
./gc.go:13:12: new(B) escapes to heap
./gc.go:20:18: make([]int, 1000000) escapes to heap
./gc.go:17:15: main make([]*B, 10) does not escape
所以尽管你已经没有bs
,但是bs指向的切片仍然被gc认为是在堆栈上。如果你把你的代码推送到它自己的func,然后GC返回它,你会看到GC确实回收了所有的内存。
func main() {
alloc()
runtime.GC()
time.Sleep(time.Second * 2)
}
func alloc() {
var bs = make([]*B, 10)
for i := 0; i < 10; i++ {
bs[i] = NewB()
bs[i].bb = make([]int, 1000000)
}
time.Sleep(time.Second)
println("begin gc")
bs = nil
runtime.GC()
}
begin gc
gc 5 @1.003s 0%: 0.003+0.052+0.021 ms clock, 0.026+0/0.036/0.055+0.17 ms cpu, 76->76->76 MB, 137 MB goal, 8 P (forced)
gc 6 @1.003s 0%: 0.001+0.037+0.018 ms clock, 0.010+0/0.036/0.023+0.15 ms cpu, 76->76->0 MB, 152 MB goal, 8 P (forced)