判定哪些类要进行垃圾回收(可达性分析)->垃圾回收算法(复制+标记-整理)->垃圾回收器(垃圾回收算法的实现)
一、方法区(永久代,1.8元空间)的回收
方法区的回收主要回收两部分内容:废弃常量和无用的类。其中,废弃常量的回收与Java堆对象回收类似。
1.1 废弃常量
String str="abc";
str=null;
如果当前系统没有任何一个String对象引用常量池中的"abc"常量,也没有在其它地方引用这个字面量,如果此时发生GC并且有必要(内存不够用)的话,这个"abc"常量有可能被回收,清理出常量池。
1.2 无用类的回收
判断一个类是无用类,必须满足以下三个条件:
1)该类的所有实例都已经被垃圾回收(Java堆中不存在该类的任何实例)
2)加载该类的类加载器ClassLoader也已经被回收
3)该类对应的Class对象没有在任何其它地方被引用(即无法通过反射访问该类的属性、方法)。
JVM会对满足以上三点的无用类进行回收(类卸载),但仅仅是”可能“。
大量使用反射、动态代理的场景下,JVM会定期对方法区进行回收,防止永久代溢出。
二、垃圾回收算法(针对的是Java堆)
2.1 标记-清除算法
工作流程:算法分为"标记"、"清除"两个阶段:首先标记出所有需要回收的对象(标记阶段),在标记完成后统一回收所有被标记的对象(回收阶段)。
缺点:
1)效率问题:标记和清除这两个阶段的效率都不高。
2)空间问题:会产生大量不连续碎片。
2.2 复制算法(新生代垃圾回收算法)
工作流程:将内存划分为大小相等的两块,每次只使用其中一块,另一块作为保留区域。当进行垃圾回收时,将使用区域的存活对象一次性按顺序复制到保留区域,而后一次性清空使用区域。
使用场景:新生代垃圾回收。
98%的新生代对象具有朝生夕灭的特性(新生代对象存活率低)
优点:实现简单、运行高效、无空间碎片问题。
JVM采用的复制算法:
将内存划分为一块较大的Eden区域和两块大小相等、空间较小的Surivivor区域。(Eden:Survivor=8:1)。每次使用Eden区和其中的一块Survivor区域(第一块Survivor区域From区,另外一块To区)。
在进行垃圾回收(Eden区快满时)时:
1)第一次进行GC时,将Eden区中的存活对象移动到From区。
2.)第二次再次进行GC时,将Eden区和From区存活对象移动到To区,然后一次性清理掉Eden区和From区,
3)第三次进行GC时,将Eden区和To区存活的对象移动到From区,然后一次性清理掉E
den区和To区。以此循环。
4)对象在From区和To区来回移动15次(默认),将此对象移动到老年代。
特殊情况:当Survivor区域放不下存活对象时,会从老年代进行分配担保。
空间使用率:(8+1)/10=90%
2.3 标记-整理算法(老年代垃圾回收算法)
复制算法在对象存活率较高时,会有大量对象复制算法,效率很低。因此,老年代不采用复制算法。
工作流程:标记阶段和标记-清除阶段一样,标记出无用对象。
整理阶段:将存活对象向一端移动,而后一次将存活对象边界以外的空间清理掉。
2.4 分代回收算法
Java采用分代回收算法。新生代采用复制算法,老年代采用标记-整理算法。
将内存划分为新生代(对象存活率低)和老年代(对象存活率高)。
注意:永久代是方法区,新生代和老年代都和永久代没有关系。
面试题:请问了解Minor GC吗?了解Major GC吗?
Minor GC(新生代GC):指的是新生代垃圾回收,在新生代中,对象大多朝生夕灭,因此采用复制算法。Minor GC发生频繁,效率较高。
Major GC(Full GC):指的是发生在老年代的垃圾回收。出现Full GC,通常会至少伴随发生Minor GC(并非绝对),Full GC速度比Minor GC慢10倍以上,发生效率较低。
三、垃圾收集器
三个概念:
并行:指的是多条垃圾回收线程并行工作,而用户线程等待。
并发:用户线程与垃圾回收线程同时执行(不一定执行,可能会交替执行),用户线程继续执行,垃圾回收线程运行在另外的内核上。
吞吐量:CPU运行用户代码时间/CPU总时间(用户代码时间+垃圾回收时间)
新生代垃圾回收器:Serial、ParNew、Parallel、Scavenge
老年代垃圾回收器:Serial、Old、Parallel、Old、CMS
全区域垃圾回收器:G1
1.Serial收集器(新生代垃圾回收,串行收集器)
特性:Serial是一个单线程收集器。在Serial进行垃圾收集时,必须暂停其它所有工作线程,直到Serial收集器收集结束。(STW)
应用场景:Serial收集器是JVM运行在Client模式下默认新生代收集器。
优点:简单而高效。对于单核CPU,Serial收集器由于没有线程交互开销,可以获得最高的单线程收集效率。
2.ParNew收集器(新生代收集器,并行GC)
特性:ParNew收集器是Serial收集器的多线程版本。
应用场景:ParNew是许多运行在Server模式下的JVM首选新生代收集器。
优点:随着可使用CPU数量(>2)的增加,对于GC时系统资源的利用有较大帮助。
3.parallel Scavenge收集器(新生代收集器,并行GC)(“吞吐量优先收集器)
特性:吞吐量
两个参数控制吞吐量:
1).XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间
2).XX:GCRatio:直接设置吞吐量大小
应用场景:高吞吐量,适合需要与用户交互的程序(B/S架构),良好的响应速度能提升用户体验。
优点:与ParNew收集器比较:高吞吐量 GC自适应调节策略(-XX:+UseAdaptiveSizePolicy)
4.Serial Old收集器(老年代收集器,串行GC)
特性:Serial Old是Serial收集器的老年代版本,单线程收集器,使用标记-整理算法。
应用场景:
1)Client模式:Serial Old主要也在于给Client模式下的虚拟机使用。
2)Server模式:作为CMS收集器的后备预案,当CMS发生并发失败问题时使用。
5.Parallel Old收集器(老年代收集器,并行GC)
特性:Parallel Old是Parallel Scavenge老年代版本。
应用场景:注重吞吐量以及CPU资源敏感场合。
6.CMS(老年代垃圾收集器,并发GC)
特性:CMS收集器是以获取最短系统停顿时间为目标的垃圾回收器。(标记-清除算法)
应用场景:B/S系统服务端。B/S系统重视服务的响应速度,希望系统停顿时间尽可能短,CMS收集器非常符合此类应用需求。
优点:并发收集、低停顿。
缺点:对CPU资源敏感、无法处理产生大量空间碎片。
7.G1(全区域垃圾回收器)
应用场景:应用低停顿场景