1.内存回收
1.1 判断对象是否存活
垃圾收集器会对不再被使用的对象进行GC操作,那么就要判断一个对象是否存活,有以下几种算法:
1.1.1 引用计数算法
概述:对堆内存中的每个对象添加一个引用计数器,有其他地方引用它计数器加一,引用断开就减一。
优点:算法时间简单,判端高效。
缺点:难以解决对象之间循环引用的问题。
class O {
public Object o;
}
O oa = new O();
O ob = new O();
oa.o = ob;
ob.o = oa;
1.1.2 可达性分析算法
概述:GC Roots作为根引用点,当一个对象从GC Roots往下追溯无法被到达时,那这个对象就不可用,可以被GC。
图上左边的对象都是GC Roots可达的,不可回收,右边的对象是可以回收的。
可以作为GC Roots的对象包括:
-
虚拟机栈(栈帧中的本地变量表)中引用的对象。
-
方法区中类静态属性引用的对象。
-
方法区中常量引用的对象。
-
本地方法栈中JNI(即一般说的Native方法)引用的对象。
1.2 引用类型
强引用是正常new出来的引用,垃圾收集器不会回收强引用对象。
软引用是有用但不是必需保留的对象,弱于强引用,当系统内存宽裕时不会回收这些对象,但是如果内存紧张,将要有溢出风险时,会考虑回收软引用对象。
弱引用是比软引用更弱一些的引用对象,弱引用对象只能存活到下一次GC到来之前,不管下一次的GC时内存是否充裕,弱引用对象都会回收。
虚引用是最弱的引用,虚引用的作用仅仅是在运行时该对象被回收后获得通知。
1.3 垃圾收集算法
1.3.1 标记-清除算法
概述:通过上面讲到的算法来判断每个对象是否要被回收,如果要被回收,则加上标记,标记完成后对所有被标记的对象统一回收。
缺点:标记和清除的过程效率不高;清除之后会有大量不连续的内存碎片,这些被清除后产生的可用内存不能组成连续内存,无法给内存需求较大的对象分配空间。
1.3.2 复制算法
概述:将内存分成两半,每次只使用其中一半的区域,当一半内存耗尽时,将还存活的对象复制到另一半区域,同时回收当前部分的内存。
优点:解决了标记-清除算法带来的内存碎片问题。
缺点:只能使用一半内存,另一半处于空闲,太过浪费。
HotSpot虚拟机的复制算法使用的是一块Eden空间和两块Survivor控件,大小是8:1:1,用来回收新生代对象,(新生代对象被回收的概率大)。每次使用Eden控件和一块survivor空间,回收后将存活的对象复制到另一块survivor空间,然后清除Eden和上一个survivor。这样有效地降低内存浪费。但是对于老年代的对象回收则不那么适用。
1.3.3 标记-整理算法
标记的过程和标记-清除算法类似,但是在清除无用对象之后,还需要将存活的对象向内存空间的一端移动,并更新引用其对象的指针。
优点:不会产生内存碎片。
缺点:增加了移动过程,增加算法成本。
1.3.4 分代收集算法
商业虚拟机普遍采用的算法,将java堆分为“新生代”和“老年代”,对新生代采用复制算法,对老年代采用标记-整理算法。
2 垃圾收集器
2.1 Parallel Scavenge收集器
Parallel Scavenge收集器的目的是想要达到一个可控制的吞吐量,它不是一味的缩短垃圾收集停顿时间或者控制每次GC的大小,而是吞吐量的精确控制。
吞吐量是CPU执行用户代码的时间和CPU运行总时间的比值,这个比值越大,吞吐量越大,CPU的时间利用效率越高。
-XX:MaxGCPauseMillis:控制每次GC最大暂停时间
-XX:GCTimeRatio: 控制吞吐量比率,是一个1-100的整数值,计算公式为1/(1+ratio)
-XX:UseAdaptiveSizePolicy: 自适应调节策略,可以根据当前系统性能情况自动调节参数选择合适的GC停顿时间和吞吐量,做到自动优化。
2.2 CMS收集器
CMS收集器全称Concurrent Mark Sweep,目标是为了获取最短的GC停顿时间,基于“标记-清除”算法。分为四个步骤:
初始标记
快速标记和GC Roots直接连接的对象,stop the world
并发标记
追溯GC Roots关联的对象
重新标记
因为是并发收集,修正因期间执行代码标记改变的部分,stop the world,时间长于初始标记,远短于并发标记
并发清除
清除不存活的对象
优点:并发手机,低停顿时间
缺点:
1、CPU资源敏感,
2、无法处理浮动垃圾(上一次清理阶段用户继续产生的垃圾)
3、标记-清除算法产生内存碎片
2.3 G1收集器
Garbage-First是从JDK 7正式使用的收集器,到最新的JDK 10都一直在使用,采用的“标记-整理”,局部采用“复制”算法,不会像CMS一样产生内存碎片。
可以看文章Getting Started with the G1 Garbage Collector
基本步骤:
初始标记
并发标记
最终标记
筛选回收
参考资料
- 深入理解Java虚拟机:JVM高级特性与最佳实践
- Getting Started with the G1 Garbage Collector