Java垃圾回收

    垃圾回收主要回收的是堆内存,基于分代的思想,分为新生代和老年代。本篇主要涉及到JVM中对象分配、对象晋级、对象的生死判定、对象回收、垃圾回收器以及一些垃圾回收的面试题。

目录

垃圾回收的一些基本概念

■JVM中堆内存分配

■ 对象分配

■ 对象晋级

■ 对象生死判定

对象回收方法论——分代收集

■ 新生代——标记清除法

■ 新生代——复制算法

■ 老年代——标记整理算法

垃圾回收器

垃圾回收相关面试题


垃圾回收的一些基本概念

■JVM中堆内存分配

■ 对象分配

  ☛ 优先在Eden区分配。当Eden区没有足够空间分配时,VM发起一次Minor GC(回收新生代垃圾),将Eden区和其中一块Survivor区内尚存活的对象放入另一块Survivor区域。如Minor GC时,Survivor空间不够,对象提前进入老年代,老年代空间不足时进行Full GC;

  ☛ 大对象直接进入老年代,避免在Eden区和Survivor区之间产生大量的内存复制,此外大对象容易导致还有不少空闲内存就触发GC以获得足够的连续内存空间(数组)。

注:Minor GC相当于是轻量级的垃圾回收,VM频繁的进行Minor GC是无所谓的,而应当避免Full GC,因为尽管随着jdk版本的提升,GC效率越来越高,但是仍然是很消耗性能的!

 

■ 对象晋级

  ☛年龄阈值:VM为每个对象定义了一个对象年龄(Age)计数器。经第一次Minor GC后仍然存活,被移到Survivor空间中,并将年龄设置为1。以后对象在Survivor区中每熬过一次Minor GC年龄就+1,当增加到一定程度(-XX:MaxTenuringThreshold,默认15),将会晋升到老年代。

  ☛ 提前晋升:动态年龄判定,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,而无需等到晋升年龄。

 

■ 对象生死判定

可达性分析算法 —— 通过一系列的称为GC Roots的对象作为起点,然后向下搜索;搜索所走过的路径称为引用链/Reference Chain,对象当一个到GC Roots没有任何引用链相连时,即该对象不可达,也就说明此对象是不可用的。

 

 

 

对象回收方法论——分代收集

■ 新生代——标记清除法

    该算法分为“标记”和“清除”两个阶段,首先标记出所有需要回收的对象(可达性分析),在标记完成后统一清除掉所有被标记的对象。

缺点:①效率问题 —— 标记和清除的效率都不高;

           ②空间问题 —— 标记和清除操作后会产生大量不连续的内存碎片,空间碎片太多可能会导致在运行过程中需要给较大对象分配内存时,无法找到足够的连续内存而不得不提前触发另一次垃圾回收。

 

■ 新生代——复制算法

    该算法的核心是将可用内存按容量划分成大小相等的两块,每次只用其中一块,当这一块的内存用完,就将还存活的对象复制到另一块上,然后把使用过的内存空间一次性清理掉。

优点:①由于每次都对整个半区进行内存回收,内存分配不必考虑内存碎片问题;

          ②垃圾回收后内存连续,只需要移动堆顶指针,按顺序分配内存即可;

          ③特别适合java对象朝生夕死的特点。

缺点:①内存大小减为原来的一半,太浪费了;

          ②对象存活率较高的时候,需要执行较多的复制操作,效率变低;

          ③如果不使用50%的对分策略,老年代需要考虑空间的担保策略。

 

■ 老年代——标记整理算法

   该算法分为“标记”和“清除”两个阶段,首先标记出所有要回收的对象(可达性分析),在标记完成后让所有存活的对象向一端移动,然后清理掉端边界以外的对象。

优点:①不会损失50%的空间;

          ②垃圾回收后内存连续,只需要移动堆顶指针,按顺序分配内存即可;

          ③比较适合有大量存活对象的垃圾回收;

缺点:标记/整理算法唯一的缺点就是效率也不高,不仅要标记所有存活对象,还要整理所有存活对象的引用地址。从效率上讲,标记整理算法的效率低于复制算法。

 

垃圾回收器

垃圾回收器
收集器收集对象和算法收集器类型说明适用场景
Serial(最古老的)

新生代 

复制算法

单线程进行垃圾回收时,必须暂停掉所有工作线程,直到完成;(Stop the world耗时长,后面的几种回收器主要是为了减短这个时间);简单高效,适合内存不大的情形;
ParNew

新生代

复制算法

并行的多线程收集器ParNew垃圾收集器是Serial的多线程版本

运行在server模式下的虚拟机首选;

搭配CMS垃圾回收器的首选;

Parallel Scavenge

吞吐量优先收集器

新生代

复制算法

并行的多线程收集器类似ParNew,更加关注吞吐量,达到一个可控制的吞吐量,jdk默认的新生代垃圾收集器;本身是Server级别多CPU机器上的默认GC方式,良好的响应速度能够提高用户体验,主要适合后台运算不需要太多交互的任务;
Serial Old MSC

老年代

标记整理算法

单线程 Client模式下,虚拟机使用
Parallel Old

老年代

标记整理算法

并行的多线程收集器Parallel Scavenge收集器的老年代版本,为了配合Parallel Scavenge的面向吞吐量的特性而开发的对应组合,JDK的默认老年代垃圾回收器;在注重吞吐量和CPU资源敏感的场合使用;
CMS(Jdk8及之前是主流的)

老年代

标记清除算法

并行与并发的收集器尽可能缩短垃圾回收时用户线程停止时间。缺点(标记清除算法造成的):1.内存碎片,2.需要更多CPU资源,3.浮动垃圾问题,需要更多的堆空间;重视服务的响应速度、系统停顿时间和用户体验的互联网网站或者B/S系统,互联网后端CMS是主流的垃圾回收器(Jdk9之前);
G1(Jdk7引入,Jdk9成为默认)

跨新生代和老年代

标记整理+化整为零

并行与并发的收集器JDK1.7正式引入,采用分区回收的思维,基本不牺牲吞吐量的前提下完成低停顿的内存回收;可预测的停顿是其最大的优势面向服务端应用的垃圾回收器;目标为取代CMS。

注:吞吐量=运行用户代码时间/(运行用户代码时间+垃圾回收时间)

  垃圾回收时间=垃圾回收频率*单次垃圾回收时间

G1对堆内存的划分不同于前面对新生代和老年代一整块一整块划分,而是细分成一小块一小块的,内存划分示意图如下:

 

垃圾回收相关面试题

★垃圾回收常用算法,特点?

    新生代-标记清除算法、新生代-复制算法、老年代-标记整理算法。(特点上面有总结)......

★常见垃圾回收器,优缺点,重点讲CMS?(见上面的表)

★完成一次GC的流程(从ygc到fgc),重点讲讲对象如何晋升到老年代?

★JVM垃圾回收机制,何时触发MinorGC和FullGC?

    从新生代(包括Eden和Survivor区)回收内存被称为Minor GC;对老年代GC称为Major GC,而FullGC是对整个堆来说的,FullGC时间比较慢,而且会占用CPU的时间片。

Minor GC触发条件 ——  当Eden区满时,触发Minor GC;

 Full GC触发条件(避免) —— 

    ①System.GC();  

    ②老年代空间不足;   

    ③永生区(JDK8中无永生区了)空间不足;   

    ④统计得到的Minor GC晋升到旧生代的平均大小大于老年代的剩余空间;

    ⑤堆中分配很大的对象(指需要大量连续内存空间的java对象,例如很长的数组)。详见https://www.cnblogs.com/sunshisonghit/p/7448224.html

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值