7 垃圾回收
7.1 判断对象是垃圾对象
两种方法
- 引用计数法
- 可达性分析法
引用计数法
在对象中添加一个引用计数器,当有地方引用这个对象的时候引用计数器的值就加一,当引用失效的时候这个值就减一;
实现简单,判断效率高.
现在没有在用这个,因为现在很多对象都是相互引用.导致这个对象是否还在引用.无法回收.
package com.xbb.test;
/**
* 如何打印垃圾回收日志
* 参数 :
* verbose:gc ---> 输出一些简单信息
* -xx:+PrintGCDetails --->输出一些GC明细信息
*
* VM Options : -verbose:gc -XX:+PrintGCDetails
*/
public class GCDemo {
public static void main(String[] args) {
int a = 123;
System.out.println(a);
}
}
可达性分析法
相对引用计数法较复杂.但执行效率比较强大.弥补了引用计数法无法判断相互引用的弊端.
原理 : 不断的去从一个对象里面找引用的那个对象.判断是否能够到达那个对象.如果能达到那个对象则代表对象还在使用.如果到不了.则代表对象已经不再使用.可以回收.
官方 : 从GCRoot节点开始.把相互引用的每个对象之间的连线称为引用链.如果检测到这个引用链中的某一个对象没有连接在这个引用链上了.则判断这个对象不可用可以进行回收.
RCRoot作用对象 :
- 虚拟机栈(局部变量表).
- 方法区的类属性所引用的对象.
- 方法区中常量所引用的对象.
- 本地方法栈所引用的对象.
7.2 如何回收
- 回收策略
- 标记-清除
- 标记-整理
- 复制算法
- 分代回收算法
标记清除算法
已经淘汰不再使用
针对老年代
基础算法,相对简单.两个过程,一个标记一个清除.
两大问题 效率不高(两次扫描,耗时严重).会出现内存碎片.
复制算法
主要发生在新生代中.
堆内存中分为新生代与老年代(GC不太关注).
新生代分为:
Eden(新创建的对象都会丢到这里面),GC最多关顾的区域,GC关顾的时候如果有可以回收的对象则被回收.没有被回收的对象则会丢到Survivor中
Survivor(存活区)
Tenured Gen(GC很少关顾)
复制算法把内存分为了两块,JVM在用的时候只用其中的一块.当GC关顾的时候把被标记的对象回收掉.把没有标记的对象统一移动到另外一块内存中并且排列整理好.
在下一次GC关顾前系统会使用这一块内存区域.以此反复.
缺点:浪费内存.所以经过研究把堆内存分为三块,分别是Eden(80%),Survivor(10%),Survivor(10%).当我们创建对象的时候直接丢到Eden区域.GC在回收Eden区域的时候.把失效的对象进行回收.把活着的对象统一复制到Survivor,当GC在回收第一块Survivor区域的时候.把失效的对象回收掉.把活着的对象复制到另一块Survivor区域中.以此反复.
标记整理算法
针对老年代
因为老年代中的这些对象失效的概率小.所以每次产生的垃圾并不多,在进行回收的时候.把存活的对象移动到内存区域的某一条边界线一边.把失效的移动到另一边.这样GC就一次性回收掉失效的部分.
分代收集算法
采用标记整理算法和复制算法进行结合使用.复制算法主要处理的是新生代.标记整理算法处理的是老年代.所以二者结合使用各司其职.
7.3 垃圾回收器
- Serial
- Parnew
- parallel
- Cms
- G1
Serial
客户端使用
最基本.出现最早. JDK1.3之前,JVM回收新生代唯一的选择.
单线程垃圾收集器,如果系统正在运行.多个线程正在进行工作.此时需要进行垃圾回收.就会暂停正在工作的线程.让GC线程独立工作.GC回收完成后暂停的线程继续工作.
parallel
服务端使用.
采用复制算法.作用于新生代,无法与Cms一起使用.
多线程.
关注吞吐量(执行用户代码所用的时间和执行用户代码加垃圾回收所消耗的时间的总体比值.),
可以通过参数来缩短每次GC时间.但总垃圾量不会变.缩短时间必然会增大次数.适用于访问量较少的服务中.
Parnew
作用新生代
比Serial相比只是多了一个多线程.其他都一样.
多线程垃圾回收,与Serial相同.系统运行过程中.多个线程正在进行工作.此时需要进行垃圾回收.就会暂停正在工作的线程.生GC线程进行工作.Parnew与Serial不同的是.Parnew是多
线程的.相比单线程回收就会提高回收速度.缩短间隔.
JDK1.5时.CMS出现.他是真正做到GC回收与工作线程同时执行.不需要暂停工作线程.但是他是用于回收老年代内存的.
关注点 :
Cms
Concurrent mark sweep
作用于老年代
并发垃圾收集器
采用标记清除算法.性能低.需要通过
与Parnew分工合作回收新生代与老年代垃圾.
JDK1.5时.CMS出现.他是真正做到GC回收与工作线程同时执行.不需要暂停工作线程.但是他是用于回收老年代内存的.
优点 : 并发收集,低停顿
缺点 : 占用大量CPU资源.无法处理浮动垃圾(刚打扫完又丢的垃圾称为浮动垃圾).出现Concurrent Mode Failure,产生内存碎片.
工作过程
- 初始标记
- 标记可以被GC回收的对象(通过可达性分析法),只标记GCRoot能直接关联到的对象.不标记直接关联对象的子对象.所以这个过程是非常快的.
- 并发标记
- 标记GCRoot直接关联对象的后续失效对象
- 重新标记
- 标记并发标记期间因用户程序继续运行导致的对象变动,相当于修正并发标记
- 并发清理
并行 : 多个线程同时工作称为并行
并发 : 多种线程同时工作称为并发
1,并行(Parallel):多个垃圾收集线程并行工作,此时用户线程处于等待状态
2,并发(Concurrent):用户线程和垃圾收集线程同时执行
G1收集器
当今收集器中龙头老大位置.
服务端使用
工作过程
- 初始标记
- 并发标记
- 最终标记
- 筛选回收
优势 :
- 并行与并发
- 分代收集
- 空间整合
- 可预测的停顿
https://blog.csdn.net/rlnlo2pnefx9c/article/details/79722384