垃圾回收
打印垃圾回收日志信息:-verbose:gc -xx:+PrintGCDetail
由java虚拟机来进行管理,无需程序员进行处理
一、如何判定对象何时变为垃圾
1、引用计数法(弃用)
在对象中添加一个引用计数器,当有地方引用该对象时,引用计数器的值加一,当引用失效时,计数器的值减一,当计数器的值为0时,则视为该对象为垃圾
优点:实现简单,判定效率高
缺点:最外层引用失效(该内存以及 为垃圾),但是内部进行引用过,无法释放,造成计数器值不为0,无法进行内存释放
2、可达性分析
定义GCRoot根节点,从该对象往下搜索,他所走过的路径称为引用链,当该内存没有被任何引用链引用时,该内存被视为垃圾
作为GCRoot对象:
虚拟机栈(局部变量表)
方法区的类属性所引用的对象
方法区中常量所引用的对象
本地方法栈中所引用的对象
二、如何回收
1、回收策略
标记-清除算法:对垃圾内存进行标记,调用清除程序来清空内存,缺点(久而久之,很难找到一块比较较大的完整的内存)
复制算法(针对新生代内存的收集):把内存分成大小相等的两块,每次使用其中一块,当垃圾回收的时候,把存活的对象复制到另一块上,
然后把这块内存整个清理掉。复制算法实现简单,运行效率高,但是由于每次只能使用其中的一半,造成内存的利用率
不高。现在的 JVM 用复制方法收集新生代,由于新生代中大部分对象(98%)都是朝生夕死的,所以两块内存的比例
不是 1:1(大概是 8:1)。
共享区:堆内存(垃圾回收主要区域),方法区 独占区:栈内存,本地方法栈,程序计数器
堆:
新生代:
Eden(伊甸园)
survivor(存活区)
Tenured Gen()
老年代:
标记-整理算法(针对老年代的垃圾回收):该区域对象被回收的概率低,先进行标记垃圾对象,没有被定为垃圾对象的对象向内存的一端进行移动从而获得完整的内存
分代收集算法:对不同的内存区域选择不同的垃圾回收算法
2、垃圾回收器
serial:最基本,发展最悠久,单线程垃圾收集器,当垃圾回收线程启动时,所有其他线程全部暂停
parnew(新生代收集器):与serial相比变成了多线程垃圾回收
parallel(新生代收集器):多线程收集器,与parnew相比,可以达到可控制的吞吐量;
吞吐量:CPU用于运行用户代码的时间与CPU消耗总时间的比值;CPU消耗总时间为CPU用于运行用户代码的时间与垃圾回收时间的综总和
-XX:MaxGCPauseMillis:垃圾收集器最大停顿时间
-XX:GCTimeRatio :吞吐量大小(0,100)
Cms(老年代垃圾收集器):concurrent Mark Sweep 并发垃圾收集器
工作过程:
初始标记
并发标记
重新标记
并发清理
优点:
并发收集
低停顿
缺点:
占用CPU资源大
无法处理浮动垃圾
出现concurrent Mode Failure
空间碎片
G1:充分利用多核CPU的优势,缩短停顿时间,并行+并发,分代收集,可预测停顿,空间整合
步骤:初始标记,并发标记,最终标记,筛选回收
三、何时回收