Java垃圾回收概览

时间:2021-10-31 14:58:27

GC要解决三个主要的问题:

  • 哪些内存需要回收?
  • 什么时候回收?
  • 如何回收?

哪些内存需要回收?

最简单的是引用计数(reference count),缺陷是无法解决循环引用。于是更快点的算法是可达性分析(reachable analysis)。

什么时候回收?

至少要经历两次标记过程:

  1. 在进行可达性分析后,发现没有与GC roots相连接的引用链时,会被第一次标记并进行一次筛选——是否有必要执行finalize()。
    • 对象没有finalize()方法或者被虚拟机执行过,视为“没必要执行”
    • 有必要执行finalize(),被放置于F-Queue队列中,并在稍后由(虚拟机自动建立的、优先级低的)Finalizer线程去“执行”(触发相应方法,但并不会等待它完成)。
  2. 之后GC将对F-Queue中对象进行第二次小规模的标记。

如何回收?

  1. Mark-Sweep(标记-清除):(缺陷:会造成大量的内存碎片。)
  2. Copy:内存一分为二,每次只使用其中的一半。清理时,将存活对象拷贝到未使用的另一半,再将已用的这一半清理掉。(缺陷:将内存缩小为原来的一半,在存活对象较多时效率很低。所以在新生代区域会使用这种算法,一大块Eden和两块Survivor区域。每次使用Eden和其中一块Survivor区域。)
  3. Mark-Compact(标记-整理):让所有存活的对象,往一端移动,适用于存货对象较多的区域,如老生代。
  4. 分代收集:综合了以上所有方法,对不同的generation区域使用不同的算法。

参考文献