JVMGC
»深入理解Java虚拟机读书笔记目录:
判断对象是否存活的方法
垃圾收集器对对象进行回收时第一件事就是判断哪些对象还活着,哪些对象已经死了,垃圾收集器将回收死掉的对象。通常有以下两种方法判断对象是否存活。
(1) 引用计数法
在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1,当引用失效时,计数器值减1,计数器为0的对象就是死掉的对象。
引用计数法实现简单,判定效率高,但是主流的java虚拟机内并没有使用该方法管理内存,因为它不能解决对象间相互循环引用的问题。
(2) 可达性分析算法
通过一系列”GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到”GC Roots”没有任何引用链相连时,则证明该对象死掉了。
GC Roots包括下列几种:
- 虚拟机栈中引用的对象
- 方法区中静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中native引用的对象
以上两种方法都用到了引用,引用分以下几种:
- 强引用:只要强引用存在,垃圾收集器永远不会回收被引用的对象
- 软引用:在系统将要发生内存溢出之前,会回收被引用的对象
- 弱引用:垃圾收集器工作时,会回收掉被引用的对象
- 虚引用:无法通过虚引用获得对象实例,被虚引用关联的对象能在这个对象被回收时收到一个系统通知。
finalize方法(避免使用):
在对象进行可达性分析后发现没有GC Roots链接,那么它会被标记,并且判断该对象是否有必要执行finalize方法,如果对象没有覆盖finalize方法或者finalize方法已经被调用过了,那么则视为没有必要执行,那么该对象会被回收,如果判断为有必要执行finalize方法,那么只要对象在finalize方法执行过程中被重新引用,则可以不被回收。
任何对象的finalize方法最多只能被执行一次。
判断类是否可以被回收需要同时满足以下三点
- 该类所有的实例都已经被回收
- 加载该类的ClassLoader已经被回收
- 该类对应的java.lang.Class对象没有在任何地方被引用
垃圾收集算法
(1) 标记清除算法
算法为标记和清除两个阶段
首先标记所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
不足之处:
- 标记和清除两个过程的效率都不高
- 标记清除后会产生大量不连续的内存碎片
(2) 复制算法
将内存划分为大小相等的两块,每次使用其中一块,当一块满了的时候,就将存活的对象复制到另一块,然后将满了的这一块全部清除。
不足之处:
- 将内存缩小为原来的一半
- 复制导致效率比较低
现在的商用虚拟机都采用这种手机算法来回收新生代,将新生代分为Eden和s0,s1
(3) 标记整理算法
标记整理算法有标记和整理两个过程,标记过程和标记清除算法一样,整理过程是将所有存活的对象移动到一端,然后直接清除掉端边界以外的内存。
(4) 分代算法
将java堆分为新生代和老年代,对新生代使用复制算法,老年代使用标记整理算法
垃圾收集器
(1) Serial收集器
Serial收集器是一个单线程收集器,它在进行垃圾回收的时候必须暂停所有其他工作线程,直到它收集结束为止。虚拟机在Client模式下默认新生代收集器就是Serial收集器。
优点:简单高效
(2) ParNew收集器
ParNew是Serial收集器的多线程版本,是许多虚拟机运行在Server模式下首选的新生代收集器
(3) Parallel Scavenge收集器
Parallel Scavenge收集器也是使用复制算法的新生代收集器,同时也是并行的多线程收集器,它的主要目的是尽可能的提高吞吐量。
吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾收集的时间)
(4) Serial Old收集器
Serial Old是Serial收集器的老年代版本,基于标记整理算法
(5) Parallel Old收集器
Parallel Old 是Parallel Scavenge收集器的老年代版本
(6) CMS收集器
CMS收集器是一种以获得最短回收停顿时间为目标的收集器。基于标记清除算法。
(7) G1收集器
G1收集器基于标记整理算法,同时可以利用多核CPU的特性。
以下是一些写的不错的博客: