一、 GC Roots
首先需要了解垃圾回收的时候需要回收那些东西,这些东西总的名字叫GC Roots,那么GC Roots 包括那些东西呢:
● 虚拟机栈(栈帧中的本地变量表)中引用的对象。
● 方法区中类静态属性引用的对象。
● 方法区中常量引用的对象。
● 本地方法栈中JNI(即一般说的Native方法)引用的对象
有两个概念,引用计数和可达性分析
1. 引用计数:当这个引用可以访问的时候+1,不能访问的时候-1,当这个引用为0的时候就进行垃圾回收。
2. 可达性分析:JVM进行垃圾回收的时候,看这个引用对象有没有被使用,就是遍历这个对象所有引用的关系,如果发现和GC Roots没有任何关系的时候就被回收了。
因为垃圾回收重点是对 堆和方法去进行回收。
堆上面主要存放的是对象的引用。所以常见的引用有四种类型:
1. 强引用,就是我们new出来的东西,Student student = new Student();
2. 软引用,就是通过SoftReference创建的对象。
看上面这段代码,软引用 后面赋值null后,后面还对这个引用进行访问,所以垃圾回收没有对这个引用进行回收。所以返回false.
3. 弱引用 通过WeakReference这个对象创建。
当进行垃圾回收后,这个对象就被回收了。
如上图,这个代码最后一行返回null。
4. 虚引用 通过PhantomReference 实现
也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
二、垃圾回收算法
1. 标记-清除
这个算法是将内存中需要回收的标记出来,然后统一进行清理。
缺点:效率低,空间利用率低。
2. 标记-整理
这个算法时间内存中需要回收的标记出来,进行整理后统一清理。
3. 复制
这个算法是将内存一分为二,然后每次用一块,垃圾回收的时候将存活的复制到另外一块,将这一块的内存全部回收,这样重复进行。
有点:运行高效
三、垃圾回收流程
新生代:当我们创建一个Student s = new Student 的时候,他在堆区的伊甸区,当经过一次垃圾回收,他将幸存的对象复制到幸存区1,在经过一次垃圾回收,他将幸存区1的对象复制到幸存区2.这样重复下去,这三块区域就组成了新生代。
新生代用的垃圾回收算法是MinorGC。新生代用的复制算法。
老年代:当新生代中的对象达到一定幸存频次如15次之后,他就将这些对象复制到老年代,老年代进行回收,老年代应用的是标记整理算法。
四、回收机制
首先要说明垃圾分类
1. 保守式GC
这种GC是JVM通过GC Roots 从上到下进行扫描,需要回收的直接进行回收。
2. 半保守式GC
在对象上记录类型的信息,在扫描的时候进行判断进行回收。
3. 准确性GC
将类的信息存放到OopMap中,然后进行准确性的扫描。
Stop the world
GC 并不是时时刻刻进行垃圾回收,所以在进行垃圾回收的时候他要进行Stop the world 就是将所有的线程停顿。
4. 可达性分析
从可达性分析中从GC Roots节点找引用链这个操作为例,可作为GC Roots的节点主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如栈帧中的本地变量表)中,现在很多应用仅仅方法区就有数百兆,如果要逐个检查这里面的引用,那么必然会消耗很多时间。
另外,可达性分析对执行时间的敏感还体现在GC停顿上,因为这项分析工作必须分析期间整个执行系统看起来就像被冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不断变化的情况,该点不满足的话分析结果准确性就无法得到保证。这点是导致GC进行时必须停顿所有Java执行线程(Sun将这个称为“Stop The World”)的其中一个重要原因,即使是在号称(几乎)不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的。
五、安全点
在OopMap的协助下,HotSpot可以快速且准确地完成GC Roots枚举,但一个很现实的问题随之而来:可能导致引用关系变化,或者说OopMap内容变化的指令非常多,如果为每一条指令都生成对应的OopMap,那将会需要大量的额外空间,这样GC的空间成本将会变得很高。
安全点太多,GC 过于频繁,增大运行时负荷;安全点太少,GC 等待时间太长。一般会在如下几个位置选择安全点:
-
循环的末尾
-
方法临返回前
-
调用方法之后
-
抛异常的位置
六、安全区域
假如线程处于Sleep或者Blocked状态,这时候线程无法响应JVM的中断请求,也就无法到达Safepoint的地方中断挂起。对于这种情况,就需要安全区域(Safe Region)来解决。
安全区域是指在一段代码片段之中,引用关系不会发生变化。在这个区域中的任意地方开始GC都是安全的。 也可以把Safe Region看做是Safepoint的扩展。