这是我参与「第五届青训营」伴学笔记创作活动的第 4 天
本篇文章内容:
- 自动内存管理
- Go 内存管理及优化
- 编译器和静态分析
- Go 编译器优化
一、自动内存管理
01.自动内存管理
-
动态内存
- 程序在运行时根据需求动态分配内存:malloc()
-
自动内存管理(垃圾回收):由程序语言的运行时系统管理动态内存
- 避免手动内存管理,专注于实现业务逻辑
- 保证内存使用的正确性和安全性:double-free problem,use-after-free problem
-
三个任务
-
为新对象分配空间
-
找到存活对象
-
回收死亡对象的内存空间
-
-
Mutator: 业务线程,分配新对象,修改对象指向关系
-
Collector: GC 线程,找到存活对象,回收死亡对象的内存空间
-
Serial GC: 只有一个 collector
-
Parallel GC: 支持多个 collectors 同时回收的 GC 算法
-
Concurrent GC: mutator(s) 和 collector(s) 可以同时执行
- Collectors:必须感知对象指向关系的改变!
-
评价 GC 算法
-
安全性(Safety):不能回收存辉的对象 基本要求
-
吞吐率(Throughput): 1 - 程序执行总时间 花在 GC 上的时间
-
暂停时间(Pause time):stop the world(STW)业务是否感知
-
内存开销(Span overhead) GC 元数据开销
-
一、手动内存管理
Go语言采用了垃圾回收机制来管理内存。Go程序中的内存分配和回收由Go运行时管理。Go使用了复制垃圾回收算法来管理内存。当程序运行时,Go运行时会定期地暂停程序执行,检查程序中未使用的对象,并回收它们占用的内存。
Go语言还支持手动内存管理。可以使用内置的new和make函数来分配内存,并使用内置的copy和append函数来操作内存。 Go语言支持两种内存分配方式:
- 使用内置的new函数来分配内存。new函数分配内存并返回指向新分配内存的指针。
package main
import "fmt"
func main() {
//使用new函数分配内存
p := new(int)
fmt.Println(*p) //0
*p = 2
fmt.Println(*p) //2
}
- 使用内置的make函数来分配内存。make函数分配内存并返回类型的零值。
package main
import "fmt"
func main() {
//使用make函数分配内存
s := make([]int, 0)
fmt.Println(s) //[]
s = append(s, 1)
fmt.Println(s) //[1]
}
Go语言还支持内存对齐,这有助于提高程序性能。Go运行时会自动对齐内存,并且不需要开发人员手动对齐内存。内存对齐是指在内存中对某一数据类型的存储地址进行调整,使得它的地址是某个特定值的倍数。这样做的目的是为了提高程序的性能,因为当内存地址对齐时,CPU可以更快地访问内存中的数据。当定义结构体时,可以使用内置的"align"关键字来指定结构体的对齐方式.
package main
import "fmt"
type MyStruct struct {
x int64
y int64
_ [0]byte
align [3]byte
}
func main() {
ms := MyStruct{x: 1, y: 2}
fmt.Println(ms)
}
这样可以指定结构体MyStruct的对齐方式。