这是我参与「第五届青训营 」笔记创作活动的第4天
预习笔记,内容学习于他人博客
自动内存管理
自动内存管理基本概念
- 是由程序语言的运行时系统管理动态内存
- 避免手动内存管理,专注于实现业务逻辑
- 保证内存使用的正确性与安全性
- golang的内存管理本质上就是一个内存池,不过内部做了很多的优化。比如自动伸缩内存池大小,合理的切割内存块等
垃圾回收
垃圾回收
即为回收死对象的内存空间,Go中栈上内存仍然由编译器负责管理回收,而堆上的内存由编译器和垃圾收集器负责管理回收,垃圾就是指向堆区申请的内存空间,随着程序的运行已经不再使用这些内存空间,这时如果不释放他们就会造成垃圾也就是内存泄露
Go采用的垃圾回收方式
从Go1.5开始使用并发标记和三色标记法,写屏障为主要,再有就是从1.8之后的混合写屏障
常见的垃圾回收算法
- 引用计数:每个对象维护一个引用技术,当被引用对象被创建或赋值给其他对象时引用计数自动+1.如果这个对象被销毁,那么计数-1,计数为0时,回收该对象
- 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记“被引用”,没有标记的则进行回收
- 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,短的放入新生代。不同代有不同的回收算法和频率
Mutator:业务线程
这一名称本质上是在指代用户态的代码。因为对垃圾回收器而言,用户态的代码仅仅只是在修改对象之间的引用关系,也就是在对象图(对象之间引用关系的一个有向图)上进行操作。
GC线程
就是负责进行垃圾回收的线程
并发GC
GC线程和用户线程同时运行
并行GC
在停止用户线程之后,多条GC线程并行进行垃圾回收
追踪垃圾回收
追踪式回收算法本身包括标记-清除(Mark-Sweep)、标记-复制(Mark-Copy)、标记-整理(Mark-Compact)这三种回收策略
Go内存管理及优化
TCMalloc
是线程缓存的malloc,实现了高效的多线程内存管理,用于替代系统的内存分配相关的函数。 特性如下:
- 大多数对象的快速、非竞争分配和释放。对象会被以两种模式进行缓存,每个线程缓存或每个逻辑 CPU 缓存。大多数分配不需要使用锁,因此多线程应用程序的争用低且可扩展性好。
- 灵活使用内存,因此释放的内存可以重新用于不同大小的对象,或者返回给操作系统。
- 通过分配相同大小的对象的 page 来降低每个对象的内存开销,从而高效的利用小空间。
- 低开销采样,可以详细了解应用程序的内存使用情况。
mmap 系统调用
mmap:进程创建匿名的内存映射,把内存的物理页映射到进程的虚拟地址空间。进程把文件映射到进程的虚拟地址空间,可以像访问内存一样访问文件,不需要调用系统调用read()/write()访问文件,从而避免用户模式和内核模式之间的切换,提高读写文件速度。两个进程针对同一个文件创建共享的内存映射,实现共享内存
编译器和静态分析
什么是静态分析
不执行代码推导程序的行为,分析程序的性质
控制流
程序的执行流程
数据流
数据在控制流速上的传递
Go编译器优化
函数内联
定义
将被调用的函数的函数体的副本替换到调用的位置上,同时重写代码以反映参数的绑定
优点与缺点
- 优点:消除调用开销,将过程间分析的问题转换为过程内分析,帮助其他分析
- 缺点:函数体变大,编译生成的Go镜像文件变大
在大多数情况下都会是正向优化,多内联会提升性能
逃逸分析
定义
分析代码中指针的动态作用域,即指针在何处可以被访问
大致思路
从对象分配处出发,沿着控制流,观察数据流。若发现指针 p 在当前作用域 s:
1.作为参数传递给其他函数;
2.传递给全局变量;
3.传递给其他的 goroutine;
4.传递给已逃逸的指针指向的对象;
则指针 p 逃逸出 s,反之则没有逃逸出 s.