GO的性能优化和内存管理 | 青训营笔记

78 阅读4分钟
这是我参与[第五届青训营]伴学笔记创作活动能够的第4天

性能优化

自动内存管理

内存管理又指垃圾回收,“垃圾回收”这个概念在我学C++的时候是没有了解到的,不过学习了数据挖掘后接触到了Python就接触到了一点,但也只是知道有这么个东西,今天这门课就详细的讲解一下垃圾回收吧, 通过自动内存管理,我们可以避免手动释放内存,将注意力专注在业务逻辑,同时还可以避免发生内存安全问题。

一个垃圾回收周期的三个任务:

  • 为新对象分配空间
  • 找到存活对象
  • 回收死亡对象的内存空间

垃圾回收相关的概念

  • Mutator:业务线程,分配新对象,修改对象指向空间
  • Collector:GC线程,找到存活对象,回收死亡对象的内存空间
  • Serial GC:串行GC,只有一个Collector
  • Parallel GC:并行GC,支持多个Collector同时回收死亡对象的空间的GC算法
  • Concurrent GC:并发GC,可以同时执行Mutator和Collector

如何评价一个GC算法?从以下几个方面评价:

  • 安全性:一个好的GC算法不会去回收一个存活的对象
  • 吞吐量:指垃圾回收器花在GC上的时间与程序执行总时间的比值
  • 暂停:指垃圾回收导致的业务线程被挂起的时间,这个时间又被称为STW
  • 内存开销:指垃圾回收器元数据占用的内存开销

一些垃圾回收算法

追踪垃圾回收算法

追踪垃圾回收算法是一种最常见的垃圾回收算法,它通过跟踪哪些对象可以通过来自某些“根”对象的引用链访问来确定哪些对象应该被释放,并将其余对象视为“垃圾”并且回收他们。 追踪垃圾回收也是目前GO使用的垃圾回收算法。

工作方式如下:

  • 标记根对象,包括静态变量,全局变量,常量,线程栈等等
  • 从根对象出发,找到所有引用根对象的可达对象
  • 清理所有不可达对象,其中又分为三步:
    • 将存活的对象复制到另外的内存空间(Copying GC)
    • 将死亡对象的内存标记为"可分配"(Mark-sweep GC)
    • 移动并且整理存活对象(Mark-compact GC)
  • 不同的对象会有不同的生命周期,垃圾回收器可能会使用不同的标记和清理策划

分代GC

分代 GC 的设计来源于分代假说(Generational hypothesis) —— most objects die young,即大多数对象在很短的生命周期内就会死亡,分配出来后很快就不再使用了。通过为年轻和年老(经历过 GC 的次数越多则越老,反之越年轻)的对象指定不同的 GC 策略,降低整体内存管理的开销。 这个我不是很清楚,是根据别人的笔记写的,大家可以去看一下这个

链接:juejin.cn/post/719024…

引用计数

确定一个对象是否存活可以依靠判断是否有其他对象依赖这个对象存活,如果有,那么这个对象就不算死亡。 为了方便统计,就引入了这个方法,其为每一个对象维护一个与之关联的引用数目,当且仅当引用计数>0的时候,该对象才会被标记为存活,否则就会被回收。当新建对象,或是将对象添加到一个集合中时增加引用计数,反之,销毁对象或是从集合中移除时减少引用计数。

GO内存管理

GO的内存分配

  • 分块:可以通过系统调用mmap()(内存映射?)提前向操作系统申请一大块内存,然后不断地将内存分配成特定的大小的块,用于对象分配;将内存分配为包含指针的大块和不包含指针的大块来有针对性地进行 GC。
  • 缓存:通过维护mcache管理一组mspan加快内存分配效率,避免重复向操作系统申请内存
  • Balanced GC

谢谢观看,如有错误请指出告诉我,请各位大佬多多指教~