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

记录JVM学习过程,参考:
周志明的《深入了解Java虚拟机》

垃圾回收算法

引用计数器算法(HotSpot中未使用)

比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。


1. 停止-复制(stop-and-copy):适用于对象存活率低时用,新生代使用

先暂停程序的运行(所以它不属于后台回收模式),然后将所有存活的对象从当前堆复制到另一个堆,没有被复制的全部都是垃圾。当把对象从一处搬到另一处时,所有指向它的那些引用都必须修正。
采用这种算法回收新生代,将新生代分为一块较大的Eden空间和两块较小的Survivor空间,大小8:1:1,每次使用Eden和其中一块Survivor,当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间,没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion)。如果另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代。

2. 标记-清扫(mark-and-sweep):对象存活率高时用,老年代

每当它找到一个存活对象,就会给对象设一个标记,这个过程中不会回收任何对象。只有全部标记工作完成的时候,清理动作才会开始。在清理过程中,没有标记的对象将被释放,不会发生任何复制动作。所以剩下的对空间是不连续的,垃圾回收器要是希望得到连续空间的话,就得重新整理剩下的对象。“标记-清扫”工作也必须在程序暂停的情况下才能进行。

3. 标记-整理(Mark-Compact):对象存活率高时用,老年代

标记过程与“标记-清除”算法一样,但后续步骤是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。此算法避免了“复制”算法的空间问题,也避免了“标记-清除”算法的碎片问题


分代收集算法(Generational Collection)

根据对象存活周期的不同将内存划分为几块,一般是把Java堆分为新生代和老年代,新生代每次垃圾收集都发现有大批对象死去,只有少量存活,用复制算法。老年代因为对象存活率高,没有额外空间对它进行分配担保,使用标记-清除或标记-整理算法,
在Java虚拟机中,内存分配以较大的“块”为单位。如果对象较大,他会占用单独的块。


内存分配策略

对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配。少数情况下也可能会直接分配在老年代中。
新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java对象大多具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。
老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(但非绝对,在Parallel Scavenge收集器的收集策略里就有直接进行Major GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。

1. 对象优先在Eden分配:

大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC

2. 大对象直接进入老年代:

大对象是指需要大量连续内存空间的Java对象,最典型的大对象就是那种很长的字符串以及数组,大对象对虚拟机的内存分配来说是一个坏消息(更坏的消息就是遇到一群“朝生夕灭”的“短命打对象”,写程序应当避免)
虚拟机提供了一个-XX:PretenureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配。这样做的目的是避免Eden区以两个Survivor区之间发生大量的内存复制。参数只对Serial和ParNew两款收集器有效,Parallel Scavenge收集器不认识这个参数

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

虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,对象年龄设为1.对象在Survivor区中每“熬过”一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),将会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。

4. 动态对象年龄判定

虚拟机并不是用选地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。

5. 空间分配担保

在发生Minor GC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代的所有对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC,尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC.
在JDK 6u24之后,HandlePromotionFailure参数失效。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值