【JVM】垃圾回收算法与内存分配策略

来源:互联网 发布:交友约会软件 编辑:程序博客网 时间:2024/05/17 23:14

垃圾回收算法与内存分配策略

一、判断对象是否已死

1、引用计数算法

根据引用计数器判断对象存活,给每个对象创建一个引用计数器。对象有被引用时 引用计数器加1,不引用引用计数器减1,当引用计数器为0时表示该对象不存活可回收。

特殊情况:在两个对象相互引用时,实际情况对象是可回收状态,但这种情况会被认为是对象存活,不可回收。


2、可达性分析算法

现在一些通用虚拟器都是通过可达性分析算法判断对象是否存活,基本思想是:在java堆中,会有一系列叫做 “GC ROOT" 作为起点向下延伸,延伸的每个节点叫做引用链,

如果延伸的引用链(对象引用)到根节点不可达,认为这个对象可回收,如下图:



3、生死还是死亡

对象通过可达性分析算法标记后,并不是“非死不可”,此时对象处于“缓刑”状态,还要经过两次标记过程,确定对象真正死亡。

如果对象覆盖了finalize()方法,GC认为是“有必要执行“的,就是可以进行二次缓刑,此时,对象会被放到F queu 对象中,会有的优先级的 Finalize 线程进行执行,在 finalize()方法中可以进行自我拯救(对象被任意对象重新引用即可),如果引用成功,第一次逃脱成功,对象进行二次标记,不被回收。GC再次回收时,二次标记对象会被回收,因为finalize 只能执行一次,对象不能再次逃脱。


二、垃圾回收算法

1、标记-清除 算法

如名称所讲,GC将要回收的对象先进行标记,然后再进行回收。

缺点:

效率低:标记和清除两个阶段效率都不高

内存问题:地址不连续,如果遇到大对象,内存不够会触发再次回收,增加回收次数,浪费资源


2、复制算法

复制算法将可用内存分为相等两部分,Eden(回收对象),Survivor(存活对象),GC将Enden可用对象复制到Survior空间内,然后回收Eden空间。

优点:只对一半区域进行回收,不用考虑空间不了连续问题;实现建单,只要移动栈顶指针即可,效率高

缺点:对象存活率较高时,会进行频繁的复制

现在虚拟机用复制算法机制进行新生代的回收,新生代的对象大多是”朝生夕死“,比较科学的Eden 和 Survior比例是8:1,HotSpot 会划分一块较大的(80%)Eden空间和两块叫小的Survior空间,将Eden 和 一个Survior 存活对象复制到另一个 Survior空间上,然后回收Eden 和 其中一个Survior死亡对象。

如上所说,新生代回收只会有10%的空间会浪费,但在一些情况下,存活的对象>10%的内存,此时,就需要老年代做担保,通过担保机制进入老年代。



3、整理-清除 算法

与标记-清除 算法比较,标记清除会造成空间不连续,整理-清除 算法先将存活对象像一端移动,然后清除掉存活对象边界以外的死亡对象。


4、分代回收算法

分代回收没有特殊的技术,只是根据新生代和老年代的特点进行选择适合的回收算法:

新生代:大多数对象”朝生夕死“,死亡对象多,存活对象少,复制回收算法可以减少回收次数,提高效率

老年代:存活对象多,存活几率高,用复制回收算法,没有额外的内存做担保,适合使用”标记-清除“或”标记-整理“回收算法。


三、内存分配策略

1、对象优先分配Eden内存区域下

对象优先分配到Eden下,当内存不够是,Eden会进行一次Minor GC,如Eden和Survior空间不够时,按照担保机制进入老年代。

2、大对象直接进入老年代

所谓的大对象是指具有大量连续内存空间的java对象,大对象对内存来说是一个坏消息,一堆“朝生夕死”的短命大对象对内存来说简直是恶梦,遇到短命大对象,导致还有空间就需要Minor GC 来清理出足够大的空间来安置大对象。

虚拟机提供了-xx:PretenureThreshold参数配置大对象内存,大对象超过配置参数内存,就直接分配到老年代,减少复制内存造成的资源消耗(新生代采用复制算法)。

3、长期存活对象进入老年代

既然虚拟机采用分代管理,那么在分配内存时就应该识别是新生代和老年代,为了识别虚拟机给每个对象定义一个年龄计数器(age),对象每次被Minor GC 一次,年龄计数器加1,当年龄计数器超过配置值(可通过-XX:MaxTenuringThreshold=15,默认是15)时,被认定为长期存活对象,会被分配到老年代。

4、动态对象年龄判定

如上长期对象进入老年代所说,长期对象根据判定达到年龄进入老年代。实际上,虚拟机对应于对象年龄的判定不是一定要求达到配置年龄,如果Survior中的相等年龄对象中和超过Surivor一半时就会直接进入老年代。

5、空间分配担保

在新生代发生Minor GC之前,先会检查老年代空闲空间是否大于新生代对象总大小:

a.如果成立,则Minor GC可确保是安全的;

b.如果不成立,则虚拟机会查看HandlePromotionfailure设置是否允许担保失败:a.如果允许,会继续检查老年代的空闲空间是否大于历次回收对象的平均大小,如大于,会进行一次Minor GC,尽管这次Minor GC有风险;b.如大于或HandlePromotionfailure设置不允许担保失败,则会进行一次Full GC。

备注:

Minor GC:Minor GC 指新生代的非存活对象的回收动作,新生代大多存储“朝生夕死”对象,回收频繁,回收速度快。

Full GC/Major GC:值老年代大对象及存活时间长的对象的回收对象,出现了Full GC 通常伴随至少一次的Minor GC,Full GC 一般比Minor GC 慢10倍。


0 0
原创粉丝点击