Go 有一个切片垃圾收集器,仅当对切片的所有引用都已失效时才释放该切片。它还具有一个 Mmap 函数,它返回一个
[]byte
,可以使用 Munmap()
显式释放它。那么这如何与 Go 的垃圾收集器一起工作呢?
如果我这样做会发生什么?
m := syscall.Mmap(...)
m2 = m[10:100]
syscall.Munmap(m)
a = m2[0]
mmap
内存的作用与来自 C 或 Go 外部的任何其他进程内存类似。 Go 的垃圾收集器不会扫描它。
Go 的运行时知道它自己的所有堆区域在哪里,因此它可以仅根据地址判断
mmap
内存不是 Go 堆的一部分。
Go 结构可以指向它,但是如果您有从映射内存返回 Go 堆的指针,垃圾收集器将看不到它们。如果您取消映射内存并在其中保留一个悬空指针并尝试使用它,您的程序将会崩溃。
如果你的程序使用了在 go 堆中分配的大的、寿命长的
[]byte
缓冲区,并将它们替换为指向映射内存的切片,你实际上可能会注意到,虽然你的内存占用量变小了,但你的 CPU 使用率却上升了。这是因为,默认情况下,Go 的垃圾收集器调整为在每个 GC 周期释放大约一半的堆。因此,通过将缓冲区移出 Go 堆,可以使堆的总大小变小,因此分配的每个字节的 GC 周期率会上升。实际上,通过首先使用大的、寿命长的缓冲区,您已经调整了 GC,以支持 CPU 吞吐量而不是内存占用。如果缓冲区被转换为 mmap
区域,它们对 GC 来说将变得不可见,因此它会看到更小的堆,并触发更多 GC 周期。