这是我参与「第五届青训营」伴学笔记创作活动的第 29 天
性能优化
目的就是减少软件不必要的消耗,充分发掘计算机的算力
原因:提高用户体验让用户使用更加流程,节约成本,提高效率
业务层优化:针对具体场景,容易获得较大性能收益
语言运行时优化:通用型
可以采用自动化性能分析工具
自动内存管理
Mutator(业务线程):分配新对象,修改对象指向关系
Collector(GC线程):找到存活对象,回收死亡对象的内存空间
Serial GC:只有一个Collector。当业务线程在执行的过程中,GC线程需要执行的时候,GC线程会暂停业务线程的执行然后使用一个GC线程来完成GC操作。GC操作结束之后才会恢复业务线程的执行
Parallel GC(并行GC):支持多个Collector同时回收的算法。和Serial GC一样的操作流程,只是在GC操作上使用了多个GC来同时进行GC操作
Concurrent GC(并发GC):mutator和collector可以同时执行。不需要暂停业务线程,在需要GC的时候会唤醒GC线程然后GC线程和业务线程同步执行
GC清理对象
GC在清理不可达对象的时候有三种清理方式
- Copying GC:将标记的对象复制到另外的内存空间,本区域内存空间全部清理
- Mark-sweep GC:将本区域死亡对象的内存空间使用freeList管理,后面讲这些内存空间分配给新的对象
- Mark-compact GC:将本区域内的存活对象移动到本区域内存空间的开头位置,下一次从本区域最后一个存活对象的位置开始分配内存空间
常常根据对象的不同的生命周期来指定不同的GC策略
一种常见的策略就是分代GC。
分代GC有一个分代假说,也就是大部分的对象new出来之后很快就不会在使用的。但是还是存在部分对象会后续使用这部分对象不会被GC,也就是说根据这个我们可以把这些对象分成年轻一代和老年一代。而年龄就是这些对象经历GC的次数,经历过2次GC但还存活的对象年龄为2。那么年轻一代由于大部分GC之后都不会存活那么可以采用copyingGC的方式,老年一代由于大部分后续仍旧会存活采用copyingGC会加大内存开销。所以我们采用mark-sweepGC
引用计数
引用计数的出发点是每个对象都会有一个关联的引用数目,如果没有引用标识对象死亡。对象存活的条件是当且仅当引用数目大于0
GO内存分配
分块
Go内存分配的目的是为了给对象分配内存空间
首先,go向操作系统申请一大块内存空间,接着将这些大块的内存空间再划分成小一点的大块的内存空间(mspan),再将这些mspan划分成一份份小块的内存空间,这里划分的容量可以不一样,然后这些划分出来的小块的内存空间就用来分配给对象。这里会根据对象的大小来分配最合适的内存空间mspan有两种
- noscan mspan:这些内存空间用来分配给不需要指针的对象(也就是说GC不需要扫描)
- scan mspan:分配包含指针的对象(GC会扫描)