垃圾回收算法与垃圾收集器

判定哪些类要进行垃圾回收(可达性分析)->垃圾回收算法(复制+标记-整理)->垃圾回收器(垃圾回收算法的实现)

一、方法区(永久代,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(全区域垃圾回收器)

应用场景:应用低停顿场景

发布了148 篇原创文章 · 获赞 32 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/smell201611010513/article/details/94216816