垃圾回收机制

276 阅读4分钟

是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战

自动垃圾收集

自动垃圾收集是查看堆内存,识别正在使用哪些对象以及哪些对象未被删除以及删除未使用对象的过程。

使用中的对象或引用的对象意味着程序的某些部分仍然维护指向该对象的指针。

程序的任何部分都补在引用未使用的对象或未引用的对象,因此可以回收未引用对象使用的内存。

注:像C这样的编程语言中,分配和释放内存是一个手动过程。

       在Java中,接触分配内存的过程由垃圾收集器自动处理。

如何确定内存需要被回收

该过程的第一步称为标记。这是垃圾收集器识别哪些内存正在使用而哪些不在使用的地方。

可达性分析算法

简单来说,将对象及其引用关系看作一个图,选定活动的对象作为GC Roots 

然后跟踪引用链条,如果一个对象和GC Roots之间不可达,也就是不存在引用,那么即可认为是可回收对象。

引用类型和可达性级别

引用类型

  1. 强引用(Strong Reference):最常见的普通对象引用,只要还有强引用指向一个对象,就不会回收。
  2. 软引用(Soft Reference):JVM认为内存不足时,才会去试图回收软引用指向的对象。
  3. 弱引用(Weak Reference):虽然是引用,但随时可能被回收掉。
  4. 虚引用(Phantom Reference):不能通过它访问对象。供了对象被finalize以后,执行指定逻辑的机制(Cleaner)

可达性级别

  1. 强可达(Strongly Reachable):一个对象可以有一个或多个线程可以不通过各种引用访问到的情况。
  2. 软可达(Softly Reachable):就是当我们只能通过软引用才能访问到对象的状态。
  3. 弱可达(Weakly Reachable):只能通过弱引用访问时的状态。当弱引用被清除的时候,就符合销毁条件。
  4. 幻象可达(Phantom Reachable):不存在其他引用,并且finalize过了,只有幻象引用指向这个对象。
  5. 不可达(unreachable):意味着对象可以被清除了。

垃圾收集算法

标记-清除(Mark-Sweep)算法:首先标识出所有要回收的对象,然后进行清除。标记、清除过程效率有限,有内存碎片化问题,不适合特别大的堆;收集算法基本基于标记-清除的思路进行改进。

复制(Copying)算法:划分两块同等大小的区域,收集时将活着的对象复制到另一块区域。拷贝过程中将对象顺序放置,就可以避免内存碎片化。复制+预留内存,有一定的浪费。

标记-整理(Mark-Compact):类似于标记-清除,但为避免内存碎片化,它会在清理过程中将对象移动,以确保移动后的对象占用连续的内存空间。

分代收集

根据对象的存活周期,将内存划分为几个区域,不同区域采用合适的垃圾收集算法。

新对象会分配到Eden,如果超过-XX:+PretenureSizeThreshold : 设置大对象直接进入老年代的阈值。

垃圾收集器

串行收集器 - Serial GC -XX :+UseSerialGC

单个线程来执行所有垃圾收集工作,适合单处理器机器。

Client模式下JVM的默认选项

串行收集器 - Serial Old  -XX :+UseSerialOldGC

可以在老年代使用,它采用了标记-整理(Mark-Compact)算法,区别于新生代的复制算法

并行收集器

并发收集器 - CMS(Concurrent Mark Sweep) GC -XX: +UseConcMarkSweepGC 

专用老年代,基于标记-清除(Mark - Sweep)算法,设计目标是尽量减少停顿时间。

采用的标记-清除算法,存在着内存碎片化问题,长时间运行等情况下发生full GC ,导致恶劣的停顿。

CMS会占用更多CPU资源,并和用户线程争抢。

减少了停顿时间,这一点对于互联网web等对时间敏感的系统非常重要,一直到今天,仍然有很多系统使用CMSGC

垃圾收集器组合