深入理解【JVM】垃圾回收


 跟同事小Q在排查内存溢出的问题的时候,然后最后确定是JVM,但是对于JVM内部机制原理,我们两眼一抹瞎,都干瞪眼了,最后还是请假大牛,才搞明白JVM如何进行垃圾回收的,赶紧来刷一波分享。

如何确定垃圾?

 在进行垃圾回收的过程中,我们需要判断一下哪些垃圾已经“死亡”,然后可以进行回收,判断有两种方式,一个是引用计数法,另一个是可达性分析法

一、引用计数法

 给对象添加一个引用计数器,然后有地方引用,计数器就加一;当没人引用,然后计数器就减一。当任何时刻计数器为0,然后就表示该对象不再被引用,然后,就标记一下,等待GC进行回收。

缺点

 很难解决循环引用的问题;例如,a.instance=b;b.instance=a,如果a 、b这两个对象不再使用,但是他们互相引用,这也是不能进行回收的。

二、可达性分析法

 通过“GC Roots”对象作为起点,走过的路径为引用链,没有引用链关联则认为“不可达”,下图C不可达.

在这里插入图片描述
 在上面中,我一直提到“引用”,你们是不是好奇,何为“引用”呢,哈哈,我再来秀一波吧。

引用

 从Java1.2之后,引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference),具体区别如下:
https://www.cnblogs.com/huajiezh/p/5835618.html
这里就不具体介绍了,然后如果有些小白还不懂的话,然后推荐一篇文章,再自己研究吧。https://www.cnblogs.com/huajiezh/p/5835618.html

垃圾回收算法

 现在我们已经确定了对象是如何回收的,然后我们根据什么算法进行回收呢。别着急,听我慢慢道来;

一、标记-清除算法

 首先是标记出需要回收的对象,然后标记完成后,统一回收被标记的对象。。
在这里插入图片描述

缺点

 一、效率问题,我们进行标记和清除两个步骤,然后在所以浪费时间比较长;二、产生碎片化严重,这样就到导致我们在进行大对象分配时,没有可用空间

二、复制算法

 为了解决效率问题,引出了这个算法;它是将容量二分为一,然后每次仅仅使用一块。当这一块内存使用完了,然后将还存活的对象复制到另外一块上,然后再把已使用过的内存空间清理掉。

优点

 效率高,因为每次仅对半个内存进行回收;不易产生碎片化。

缺点

 可用内存被压缩到了一半,如果是大对象的话,还需要额外空间的“担保”,而且如果存活的对象多的话,Coping的效率就大大降低了。

三、标记整理算法

&ems;结合了以上两个算法,为了避免缺陷而提出。标记阶段和 Mark-Sweep 算法相同, 标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。
在这里插入图片描述

四、分代收集算法

 根据对象存活周期的不同将内存分为老年代和新生代,然后根据他们的特点选择不同的算法。老年代的特点是每次垃圾回收时只是少量对象需要被回收,所以采用的是“标记整理”、“标记-清除”;而新生代每次需要大量的垃圾需要被回收,然后一般采用“复制算法”。

垃圾收集器

JAVA堆内存被分为新生代和老年代,然后我们提供了不同的垃圾回收器。具体如下:
在这里插入图片描述

一、Serial垃圾回收器

 Serial 是一个单线程的收集器,它不但只会使用一个 CPU 或一条线程去完成垃圾收集工作,并且在进行垃圾收集的同时,必须暂停其他所有的工作线程,直到垃圾收集结束。
在这里插入图片描述

优点

 Serial 垃圾收集器虽然在收集垃圾过程中需要暂停所有其他的工作线程,但是它简单高效,对于限定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率,因此 Serial垃圾收集器依然是 java 虚拟机运行在 Client 模式下默认的新生代垃圾收集器。

二、ParNew垃圾回收器

 ParNew是多线程的,其他的跟Serial收集器比较没有太多创新,但是他是需要运行在Server模式下的虚拟机中首选的新生代收集器。
在这里插入图片描述

三、Parallel Scavenge收集器

 它是一个新生代的收集器,也是使用了复制算法。也是一个多线程的垃圾回收器。他可以使程序达到一个可控制的吞吐量。这时候高吞吐量可以可以最高效率的利用CPU时间,主要是用于后台运算而不需要太多交互的任务。它跟ParNew的区别就是自适应调节策略。

四、Serial Old 收集器

 它是Serial的老年版,类似于Serial收集器,不同的是它是运行在Client默认的java虚拟机的老年代的垃圾回收器。在Server主要是两个用途:

  1. 在 JDK1.5 之前版本中与新生代的 Parallel Scavenge 收集器搭配使用。
  2. 作为年老代中使用 CMS 收集器的后备垃圾收集方案。
    3.

五、Parallel Old 收集器(多线程标记整理算法)

 在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只能保证新生代的吞吐量优先,无法保证整体的吞吐量, Parallel Old 正是为了在年老代同样提供吞吐量优先的垃圾收集器, 如果系统对吞吐量要求比较高,可以优先考虑新生代 Parallel Scavenge和年老代 Parallel Old 收集器的搭配策略。

 新生代 Parallel Scavenge 和年老代 Parallel Old 收集器搭配运行过程图:
在这里插入图片描述

六、CMS 收集器(多线程标记清除算法)

 它是老年代的垃圾回收器。目标是获取最短垃圾停顿时间,很好的提高了用户体验。它采用的是标记-清除算法。工作机制分为一下四个阶段。
在这里插入图片描述

1. 初始阶段:
 只是标记一下 GC Roots 能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。
2.并发标记
 进行 GC Roots 跟踪的过程,和用户线程一起工作,不需要暂停工作线程。
3。重新标记
 为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。
4.并发清除
 清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停工作线程。由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作, 所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行。

七、GI收集器

 Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与 CMS 收集器, G1 收集器两个最突出的改进是:

  1. 基于标记-整理算法,不产生内存碎片。
  2. 可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收。
     G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间, 优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。
    在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 33
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值