Golang垃圾回收机制详解
Golang垃圾回收机制详解
我有一个全局映射 duplicates,我在一个 for 循环中运行这个映射,每次我执行 duplicates = make(map[int]bool)。我想知道,当我们再次执行 duplicates = make(map[int]bool) 时,映射之前占用的内存是否会被释放?
你好,欢迎!所以你在做类似这样的事情:
package main
var duplicates = make(map[int]bool)
func main() {
for {
duplicates = make(map[int]bool)
}
}
嗯,在这种情况下,垃圾回收器每次只会分配一个映射所需的最小内存量(仅哈希映射的根结构),并且它会以批次的形式释放每次分配,因为垃圾回收器会在特定的时间“周期性地”运行(参见垃圾回收算法)。所以答案是否定的,并非每次都会回收,那样做成本太高了。
更多关于Golang垃圾回收机制详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我使用堆(heap)和跟踪(trace)性能分析工具(pprof)进行了测试。根据我的观察,内存会被重用,并且垃圾回收(GC)调用的开销并不大。这是代码。我使用了一个包含100000个元素的映射(map),并且没有动态改变其大小。但从堆分析中可以看到:

内存占用量本身并不算太大。如果我们查看跟踪信息,堆大小保持稳定,这表明垃圾回收器非常高效地回收了内存。
我收集了程序运行60秒内的统计数据。在我的机器上,垃圾回收的平均运行时间是 1,968,642 ns,在我看来这也不算太多。
总结一下,为你的映射分配的内存会在每次 make 调用时被重用。我建议,如果你知道映射的大致大小,请将其大小作为参数传递给 make 调用。
在 Go 语言中,当你执行 duplicates = make(map[int]bool) 时,会创建一个新的空映射,并将 duplicates 变量指向这个新映射。此时,之前映射占用的内存会变成垃圾回收的候选对象,但不会立即释放。
Go 的垃圾回收器(GC)采用并发标记-清除算法,会在堆内存达到一定阈值或到达特定时间间隔时自动触发。当 GC 运行时,它会标记所有从根对象(如全局变量、栈上的变量等)可达的对象,而之前那个映射由于不再被任何变量引用,会被标记为不可达,从而在清除阶段被回收。
因此,之前映射占用的内存会在垃圾回收器运行时被释放,但具体时机由 GC 自动管理。你可以通过 runtime.GC() 强制触发一次 GC,但不建议在生产环境中频繁使用。
示例代码:
package main
import (
"fmt"
"runtime"
)
var duplicates map[int]bool
func main() {
// 第一次分配
duplicates = make(map[int]bool)
duplicates[1] = true
fmt.Printf("初始映射: %v\n", duplicates)
// 分配新映射,旧映射成为垃圾
duplicates = make(map[int]bool)
fmt.Println("已分配新映射")
// 可选:强制触发垃圾回收(仅用于演示)
runtime.GC()
// 使用新映射
duplicates[2] = true
fmt.Printf("新映射: %v\n", duplicates)
}
在这个例子中,第一次创建的映射在第二次执行 make 后不再被引用,会在 GC 运行时被回收。内存释放是自动的,无需手动干预。

