前言
这是我参与【第五届青训营】伴学笔记创作活动第四天,今天的学习内容主要为自动内存管理方面的内容,我认为自动内存管理可以更好的提升产品性能,可以更容易获得较大的性能收益。
正文
性能优化层面
- 业务代码
- SDK
- 基础库
- 语言运行时
- OS
业务层面优化:针对特定场景,具体问题具体分析;容易获得较大的性能收益
语言运行时优化:解决文艺更通用的的性能问题;考虑更多场景,Tradeoffs
数据驱动:自动化性能分析工具pprdf;依靠数据而非猜测;首先优化最大瓶颈
自动内存管理
- 动态内存:程序运行时根据需求动态分配内存:malloc()
- 自动内存管理(垃圾回收):有程序语言运行时回收系统动态内存;避免手动内存管理,专注于业务实现业务逻辑;摆正使用正确性和安全性:double-free problem,use-after-free problem
- 三个任务:为新对象分配空间;找到存活对象;回收死亡对象的内存空间
- 评价GC算法:安全性:不能回收存活的对象(基本要求);吞吐率;暂停时间:STW(业务是否感知,越短越好);内存开销:GC元数据开销(越小越好)
- 追踪垃圾回收:对象回收的条件:指针指向关系不可达的对象;
标记根对象:静态变量,全局变量,常量,线程栈等;
标记:找到可达对象:求指针指向关系的传递闭包:从跟对象出发,找到所有可达的对象; 清理:所有不可达对象(根据对象的生存周期,使用不同标记和清理策略) - 分代GC:分类假说:most object die young;Intuition:很多对象在分配出来很快就不再使用;每个对象都有年龄:经过GC次数;目的:针对老年和年轻对象,指定不同的GC策略;不同年龄的的对象处于heap不同的区域;
- 年轻代:常规的对象分配;由于存活对象很少,可以采用copying collection;GC吞吐率很高
- 老年代:对象一致趋向于活着,反复复制开销较大;可以采用mark-sweep collection
- 引用计数:给每个对象都有一个引用数目,对象存活条件,当且仅当引用数大于0;(优点:内存管理的操作被平摊到程序执行过程中,内存不需要了解runtime的实现细节)(缺点:维护开销较大,无法回收环形数据结构,内存开销,回收时可能引入暂停)
GO内存分配
- 目标:为对象在heap上分配内存,
- 分块:提前将内存分块;对象分配:根据对象大小,选择最适合的块返回;
- 缓存:
- 优化:小对象占比较高;Go内存分配比较耗时
- Balanced GC:本质:将多个小对象的分配合并成一次大对象的分配
编译器和静态分析
- 1.静态分析:不执行代码,推到程序的行为,分析程序的性质
-
- 控制流静态分析:程序执行的流程
- 3.数据流静态分析:数据在控制流上的传递
- 4.过程内分析:仅在过程内部进行分析
- 5.过程间分析:考虑过程调用时渗透参数传递和返回值的数据流和控制流(同时分析数据流和控制流,比较复杂)
GO编译器优化
- 函数内联:优点:消除函数调用的开销,将过程间分析转化为过程内分析,帮助其他优化;缺点:函数体变大,不友好,编译生成的GO镜像变大
- Beast Mode:调整内联策略,使更多函数内联
- 逃逸分析:分析代码中指针的的东涛作用域,:指针在何处可以被访问
- 思路:从对象分配处出发,沿着控制流;观察对象的数据流,若发现指针p在当前作用域s(作为参数传递给其他参数;传递给全局变量;传递给其他goroutine;传递给以逃逸的指针指向对象);则指针p指向的对象逃逸出s,反之则没有逃逸出s
- beast mode:函数内联扩展了函数边界,更多对象不逃逸(优化:没逃逸对象可以在栈上分配;对象在栈上分配回收很快,移动sp,减少在heap上的分配,降低GC负担)
个人总结
以上是我今日的笔记,通过本节课我对go语言了解更深刻,对于编译器我以前只知道它是编程必不可少的工具,这节课过后我对编译器了解更加深刻,对于静态分析,我认为这是编辑器很重要的一个过程,同时对分析问题和解决问题的有了更好的思路,对我以后的学习过程有很大的帮助。