Menu
CoddyTech

Go 中的垃圾回收

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 23 课,共 107 课。

与 C 或 C++ 等语言不同,Go 通过垃圾回收(GC)自动管理内存。内存用完后,你不需要手动释放。Go 运行时会跟踪仍在使用的内存,并回收其余内存。

使用 new()、make() 分配内存或创建变量时,Go 的垃圾回收器会监控这些分配。一旦程序的任何部分都无法再访问某个值,GC 就会自动释放这部分内存。

func createPerson() *Person {
    p := &Person{Name: "Alice", Age: 30}
    return p  // p 会逃逸到堆上,由 GC 管理
}

func main() {
    person := createPerson()
    fmt.Println(person.Name)
    // 不再使用 person 时,GC 会回收内存
}

在这个示例中,Person 结构体分配在堆上,因为它是从函数中返回的。Go 编译器会执行逃逸分析,以确定变量可以留在栈上,还是必须移到堆上。垃圾回收器只管理堆内存。

这种自动内存管理意味着,你可以专注于构建应用程序,而不必担心忘记释放内存导致的内存泄漏。不过,了解 GC 的存在有助于你在性能重要时减少不必要的内存分配,从而编写更高效的代码。

challenge icon

挑战

简单

让我们构建一个会话管理器,演示 Go 的垃圾回收器如何处理逃逸到堆上的对象内存。你将创建动态分配并从函数中返回的会话,让 GC 管理它们的生命周期。

你将把代码分成两个文件:

  • session.go:定义一个 Session 结构体,包含 ID(字符串)、Username(字符串)和 Data(字符串切片)字段。创建一个 NewSession 函数,接收 ID 和用户名,通过返回指针在堆上分配一个新的 Session,并将 Data 切片初始化为空。再添加一个带指针接收者的 AddData 方法,用于向会话的 Data 切片追加一个字符串;并添加一个 Summary 方法,返回显示会话详细信息的格式化字符串。
  • main.go:从输入中读取会话信息,使用构造函数创建会话,向其中添加一些数据条目,并显示会话摘要。由于会话是在函数内部创建并作为指针返回的,因此它会逃逸到堆上,由垃圾回收器管理。

输入内容如下:

  • 第 1 行:会话 ID
  • 第 2 行:用户名
  • 第 3 行:要添加的第一个数据条目
  • 第 4 行:要添加的第二个数据条目

你的 Summary 方法应返回以下格式的字符串:

Session [ID] for user [Username]
Data entries: [count]
- [entry1]
- [entry2]

例如,输入 sess-001、alice、login 和 view_dashboard 时,输出应为:

Session sess-001 for user alice
Data entries: 2
- login
- view_dashboard

这里的关键在于,NewSession 函数会创建一个 Session 并返回指向它的指针。这会使 Session 逃逸到堆上,而不是留在栈上;当不再有任何引用指向它时,它就可以被垃圾回收。你的代码不需要手动释放这块内存,Go 会自动处理。

亲手试试

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 读取会话 ID
	sessionID, _ := reader.ReadString('\n')
	sessionID = sessionID[:len(sessionID)-1]

	// 读取用户名
	username, _ := reader.ReadString('\n')
	username = username[:len(username)-1]

	// 读取第一条数据
	data1, _ := reader.ReadString('\n')
	data1 = data1[:len(data1)-1]

	// 读取第二条数据
	data2, _ := reader.ReadString('\n')
	data2 = data2[:len(data2)-1]

	// TODO: 使用 NewSession 函数创建新会话
	// 由于返回的是指针,会话会逃逸到堆上

	// TODO: 使用 AddData 方法将数据添加到会话中

	// TODO: 使用 Summary 方法打印会话摘要
	fmt.Println("")
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器