1 什么是垃圾回收?

语言的使用者只用关注内存的申请而不必关心内存的释放,内存释放由虚拟机(virtual machine)或运行时(runtime)来自动进行管理。而这种对不再使用的内存资源进行自动回收的行为就被称为垃圾回收。

2 常用的垃圾回收算法

(1) 引用计数

对每个对象维护一个引用计数,当引用该对象的对象被销毁或更新时被引用对象的引用计数自动减一,当被引用对象被创建或被赋值给其他对象时引用计数自动加一。当引用计数为0时则立即回收对象。
优点:

  • 实现简单,并且内存的回收很及时。

缺点:

  • 频繁更新引用计数降低了性能。
  • 当对象间发生循环引用时引用链中的对象都无法得到释放。

    (2) 标记清除

  • 标记从根变量开始迭代遍历所有被引用的对象,对能够通过应用遍历访问到的对象都标记为“被引用”;

  • 标记完成后进行清除操作,对没有标记过的内存进行回收。

优点: 解决了
缺点: 每次启动垃圾回收都会暂停当前所有的正常代码执行,回收时,系统响应能力大大降低 !

(3) 分代回收

将堆划分为两个或多个称为代(generation)的空间。 新创建的对象存放在称为新生代(young generation)中(一般来说,新生代的大小会比 老年代小很多),随着垃圾回收的重复执行,生命周期较长的对象会被提升(promotion)到老年代中
新生代垃圾回收的速度非常快,比老年代快几个数量级,即使新生代垃圾回收的频率更高,执行效率也仍然比老年代垃圾回收强,这是因为大多数对象的生命周期都很短,根本无需提升到老年代。

3 Goang的GC算法

Golang使用的是标记清除算法, 但在此基础上改进为 “三色标记清除法”
gc的过程分为四个阶段:

  1. 栈扫描, 所有的对象最开始都是白色, 此过程
  2. 从root开始找到所有可达对象, 标记为灰色, 放入待处理队列
  3. 遍历 灰色对象队列 , 将其引用对象标记为灰色放入待处理队列, 自身标记为黑色
  4. 循环步骤3, 直到灰色队列为空, 此时所有引用对象都被标记为黑色, 不可达对象仍然为白色, 白色的就是需要进行回收的对象

    4 GC的触发时机

  • 主动触发(手动触发),通过调用runtime.GC 来触发GC,此调用阻塞式地等待当前GC运行完毕.
  • 被动触发,分为两种方式:
    • 使用系统监控,当超过两分钟没有产生任何GC时,强制触发 GC.
    • 使用步调(Pacing)算法,控制内存增长的比例,当前内存分配达到一定比例则触发.