这是我参与「第五届青训营 」笔记创作活动的第4天
一、前言
自动内存管理在Go语言运行时runtime的重要组成部分,内存分配和垃圾回收是内存管理系统的两个重要任务,如何高效地进行内存分配和垃圾回收是影响程序效率的重要因素。
二、详细知识点介绍:
垃圾回收
动态内存指的是程序在运行过程中根据需求动态分配的内存
自动内存管理又称垃圾回收(Garbage Collection, GC)指的是由运行时系统管理动态内存,能够避免手动管理内存的麻烦,使得程序员能专注于业务逻辑的实现,并且能够保证内存使用的正确性和安全性,例如由手动管理内存可能出现double-free和use-after-free等问题
Mutator指的是业务线程,分配新对象,修改对象之间的关系
Collector指的是GC线程,找到使用中的对象,回收空闲对象的内存空间
评价GC算法的标准:
- 安全性,
最基本的要求 - 吞吐率,程序实际运行时间和程序执行总时间的比率
- 暂停时间
- 内存开销,GC元数据开销
两种常见的GC技术:
追踪垃圾回收回收对象:指针指向关系不可达的对象
标记根对象,例如静态变量、全局变量、常量、线程栈等- 从跟对象开始,找到可达对象并将其
标记 清理所有不可达对象,清理策略有几种:
- 申请一片内存空间,将存活对象复制到该空间,释放原来的内存空间(Copying GC)
- 将死亡对象的内存标记为可分配(Mark-sweep GC),使用
free list管理空闲内存 - 移动并整理存活对象(Mark-compact GC),原地整理对象,标记可分配空间
清理的优化策略,分代GC(Generational GC)
分代假说:most objects die yong
- 记录每个对象的年龄,即经过GC的次数
- 将不同年龄的度喜庆分配到heap的不同区域
- 针对年轻对象使用Copying GC清理,老年对象使用mark-sweep collection清理
引用计数
时记录每个对象被引用的次数,当引用数>0时才存活
优点:
- 内存管理的操作被平摊到程序执行过程中
- 内存管理不涉及太多runtime细节
缺点:
- 维护引用技术所需开销较大,在多线程时需要通过
原子操作保证引用技术操作的原子性和可见性 - 引用技术会带来额外的内存开销
- 无法回收环形数据结构(可通过weak reference解决)
- 回收大内存时可能引发暂停
内存分配
Go的内存分配机制类似于TCMalloc: Thread-Caching Malloc,实现的思想有点类似于CPU中的L1、L2、L3缓存。每个Goroutine独占一定大小的mspan和mcentral,多个Goroutine共享一个大的堆空间。
Go语言编译器及优化
编译器是重要的系统软件,能够识别符合语法和非法的程序,生成正确且高效的代码。编译器可由几个部分组成:
- 分析部分(front end)
- 词法分析,生成词素(lexeme)
- 语法分析,生成语法树
- 语义分析,收集类型信息,语义检查
- 中间代码生成,生成intermediate representation(IR)
- 综合部分 (back end)
- 代码优化,进行机器无关优化
- 代码生成,生成目标代码
代码优化:
静态分析:不执行程序代码,推导程序行为,分析程序的性质- 控制流分析,生成控制流程图
- 数据流分析 根据控制流分析和数据流分析的信息优化代码
- 过程内分析,仅在函数内部进行分析
- 过程间分析,需要同时考虑函数之间的调用的数据流和控制流,比较复杂
三、引用参考: