JVM中有哪些垃圾回收算法,每个算法各自的优劣?


风晓
风晓 2023-12-28 14:00:16 52533 赞同 0 反对 0
分类: 资源
本文主要讲JVM中有哪些垃圾回收算法,每个算法各自的优劣?

1、新生代采用复制算法,1个Eden区,2个Survivor区。

其中Eden区占80%内存空间,每一块Survivor区各占10%内存空间,比如说Eden区有800MB内存,每 一块Survivor区就100MB内存,

平时可以使用的,就是Eden区和其中一块Survivor区,那么相当于就是有900MB的内存是可以使用的

但是刚开始对象都是分配在Eden区内的,如果Eden区快满了,此时就会触发垃圾回收。

此时就会把Eden区中的存活对象都一次性转移到一块空着的Survivor区。接着Eden区就会被清空,然后再次分配新对象到Eden区里,Eden区和一块Survivor区里是有对象的,其中Survivor区里放的是上一次Minor GC后存活的对象。

如果下次再次Eden区满,那么再次触发Minor GC,就会把Eden区和放着上一次Minor GC后存活对象的Survivor区内的存活对象,转 移到另外一块Survivor区去。


2、为什么要这样设计新生代的回收?

因为新生代的对象都是朝生暮死,存活率很低,留个100MB的Survivor区来保存存活的对象是足够的。


3、新生代垃圾回收的各种“万一”怎么处理?什么时候进入老年代?

万一垃圾回收过后,存活下来的对象超过了10%的内存空间,在另外一块Survivor区域中放不下咋整?

答:当前放对象的Survivor区域里,一批对象的总大小大于了这块Survivor区域的内存大小的50%,那么此时大于等于这批对象年龄的对象,就可以直接进入老年代了。

具体来说就是假设Survivor2区有两个对象,这俩对象的年龄一样,都是2岁,然后俩对象加起来超过了50MB,超过了Survivor2区的100MB内存大小的一半了,这个时候,Survivor2区里的大于等于2岁的对 象,就要全部进入老年代里去。

 

 

 

万一我们突然分配了一个超级大的对象,大到啥程度?新生代找不到连续内存空间来存放,此时咋整?

答:大对象直接进入老年代,有一个JVM参数,就是“-XX:PretenureSizeThreshold”,可以把他的值设置为字节数,比如“1048576”字节,就是1MB。 如果大对象不直接进入老年代而是在新生代不停的移动,来回复制,那肯定会浪费时间浪费资源。

 

 

到底一个存活对象要在新生代里这么来回倒腾多少次之后才会被转移都老年代去?

答:对象每次在新生代里躲过一次GC被转移到一块Survivor区域中,此时他的年龄就会增长一岁,默认的设置下,当对象的年龄达到15岁的时候,也就是躲过15次GC的时候,他就会转移到老年代里去。这个具体是多少岁进入老年代,可以通过JVM参数“-XX:MaxTenuringThreshold”来设置,默认是15岁。

 

 

Minor GC后的对象太多无法放入Survivor区怎么办?

现在有一个比较大的问题,就是如果在Minor GC之后发现剩余的存活对象太多了,没办法放入另外一块Survivor区怎么办?


4、老年代空间分配担保规则

如果新生代里有大量对象存活下来,确实是自己的Survivor区放不下了,必须转移到老年代去,如果老年代放不下呢?

担保原则:(minor gc之前检查老年代可用空间大小)

1、当老年代可用空间 > 新生代所有对象的总大小

此时就可以放心大胆的对新生代发起一次Minor GC了,因为即使Minor GC之 后所有对象都存活,Survivor区放不下了,也可以转移到老年代去。

2、当老年代可用空间 < 新生代所有对象的总大小

意思就是当minro gc后如果所有对象都存活了,Survivor区放不下了,肯定放不到老年代里,这时候还需要看一个参数 “-XX:- HandlePromotionFailure”的参数是否设置了 ,如果有这个参数,

那么进行下一步判断:

看看老年代的内存大小,是否 > 之前每一次Minor GC后进入老年代的对象的平均大小。举个例子,之前每次Minor GC后,平均都有10MB左右的对象会进入老年代,那么此时老年代可用内存大于10MB。这就说明,很可能这次Minor GC过后也是差不多10MB左右的对象会进入老年代,此时老年代空间是够的。

如果上述判断的结果是:老年代的空间 < 之前每一次Minor GC后进入老年代的对象的平均大小,或者参数-XX:- HandlePromotionFailure”没有设置。

此时就会直接触发一次“Full GC”,
就是对老年代进行垃圾回收,尽量腾出来一些内存空间,
然后再执行Minor GC。

如果上面两个步骤都判断成功了,那么就是说可以冒点风险尝试一下Minor GC。此时进行Minor GC有几种可能。

第一种可能,

Minor GC过后,剩余的存活对象的大小,是小于Survivor区的大小的,
那么此时存活对象进入Survivor 区域即可。

第二种可能,

Minor GC过后,剩余的存活对象的大小,是大于 Survivor区域的大小,
但是是小于老年代可用内存大小 的,此时就直接进入老年代即可。

第三种可能,触发 full gc

很不幸,Minor GC过后,剩余的存活对象的大小,大于了Survivor区域的大小,也大于了老年代可用内 存的大小。此时老年代都放不下这些存活对象了,就会发生“Handle Promotion Failure”的情况,这个时候就会触 发一次“Full GC”。

Full GC就是对老年代进行垃圾回收,同时也一般会对新生代进行垃圾回收。因为这个时候必须得把老年代里的没人引用的对象给回收掉,然后才可能让Minor GC过后剩余的存活对象进入老年代 里面。

 

如果要是Full GC过后,老年代还是没有足够的空间存放Minor GC过后的剩余存活对象,那么此时就会导致所谓的 “OOM”内存溢出了。

老年代满了 OOM 有两种可能:

1、老年代本身对象比较多,没办法回收,都是强引用

2、新生代minor gc 后对象的大小 > survive区 ,所以进入老年代,这时候老年代也放不下这些对象,所以OOM。


5、老年代垃圾回收算法 (标记整理算法,标记的是存活的对象)

其实把上面的内容都看懂之后,大家现在基本就知道了Minor GC的触发时机,然后就是Minor GC之前要对老年代空 间大小做的检查。

包括检查失败的时候要提前触发Full GC给老年代腾一些空间出来,或者是Minor GC过后剩余对象太多放入老年代内 存都不够,也要触发Full GC。包括这套规则,还有触发老年代垃圾回收的Full GC时机,都给大家讲清楚了。

简单来说,一句话总结,对老年代触发垃圾回收的时机,一般就是两个:

1、在Minor GC之前,一通检查发现很可能Minor GC之后要进入老年代的对象太多了,老年代放不下,此时需 要提前触发Full GC然后再带着进行Minor GC;

2、在Minor GC之后,发现剩余对象太多放入老年代都放不下了。

一个之前,一个之后,好好理解。


老年代的垃圾回收算法的速度至少比新生代的垃圾回收算法的速度慢10倍。

其实大家如果透彻理解了最近的几篇文章涵盖的JVM的运行原理,就会知道,所谓JVM优化,就是尽可能让对象都在 新生代里分配和回收,尽量别让太多对象频繁进入老年代,避免频繁对老年代进行垃圾回收,同时给系统充足的内存 大小,避免新生代频繁的进行垃圾回收。

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  126
统信桌面专业版【全盘安装UOS系统】介绍  121
银河麒麟桌面操作系统安装佳能打印机驱动方法  114
银河麒麟桌面操作系统 V10-SP1用户密码修改  105
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益209.03元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!