深入理解java虚拟机之 内存分配和回收策略

为什么要分代?

堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域。当然了,我们写的代码中new的对象等都存在堆内存中。
如果说堆内存没有区域划分,所有新创建的对象和生命周期很长的对象放在一个区域,随着对象越来越多触发了JVM的垃圾回收机制,而每次回收都要遍历所有的对象,这个时间成本是难以想象的,严重影响GC效率。
而有了内存分代,新创建的对象会在新生代中分配内存,而经过多次回收仍然存活下的对象或者有特殊情况的对象会移至老年代,类信息、静态变量等信息存放在永久代里。新生代中的对象存活时间短,只需要在新生代区域中频繁进行GC,而老年代中对象存活时间长,回收的频率相对就低很多了,永久代则很少进行垃圾回收。所以呢,给堆内存分代是为了提高对象内存分配和垃圾回收的效率。

内存的分配和回收策略

上一篇我们学习了GC的 收集算法和七种收集器,今天我们来学习一下内存的分配和回收策略。

  1. 优先在Eden中分配
    一般情况下 ,大多数的新对象都是在新生代中实例化的,当Eden区的空间不够的时候,发起Minor GC;

  2. 大对象直接进入老年代
    -XX:PretenureSize Threshold参数,大于此值的对象直接在老年代分配,避免在Eden区和Survivor区之间的大量的内存复制。

  3. 长期存活的对象进入老年代。
    JVM 为对象提供了年龄计数器,经过Minor GC之后仍然存活且被Survivor区容纳的,移动到Survivor区,年龄加一。每经历一次Minor GC不被清理则年龄加一,增加到一定年龄之后被移动到老年区(默认15岁,通过 -XX:MaxTenuringThreshold 设置)

  4. 动态对象年龄判定
    若Survivor区中同年龄所有对象大小总和大于Survivor空间一半,则年龄大于等于该年龄的对象可以直接进入老年代;

  5. 空间分配担保
    在发起MinorGC之前,JVM先 检查老年代最大可用连续空间是否大于新生代所有对象总空间,成立的话Minor GC确认是安全的;否则继续检查老年代的最大连续空间是否大于历次晋升到老年代对象的平均大小,大于的话进行Minor GC,否则进行Full GC;

  6. Full GC的触发条件:
    1).调用了System.gc(); 建议而非一定。很多情况下是触发FullGC,会增加间歇性停顿的次数,因此不建议使用此方法,让JVM自己去管理内存即可。我们可以通过-XX:+ DisableExplicitGC来禁止RMI远程方法调用(Remote Method Invocation)调用System.gc()。

    2)老年代的空间不足;此场景的常见情况就是之前上文中提到的大对象以及长期存活的对象直接进入老年代等,当执行Full GC之后空间仍然不足,会抛出Java.lang.OutOfMemoryError:Java Heap Space。为了避免以上两种情况引起的Full GC,我们在调优的时候尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间或者不要创建过大的对象以及数组。

    3).空间分配担保失败;使用复制算法的Minor GC需要老年代的内存空间作为担保。如果出现了HandlePromotionFailure担保失败,就会触发Full GC。

    4)JDK1.7以及之前的永久代空间不足;在JDK 1.7及之前,HotSpot虚拟机中的方法区是通过永久代实现的,永久代中存放的是一些class的信息、常量、静态变量等数据,当系统要加载、反射的类或者调用的方法较多时,永久代可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果Full GC仍然回收不了,那么JVM就会抛出如下错误信息:java.lang.OutOfMemoryError:PermGen space。为了避免PermGen占满造成Full GC现象,我们可以增大PermGen空间或转为使用CMS GC。(JDK1.8中用元空间替换了永久代作为方法区的实现,元空间是本地内存,因此减少了一种Full GC触发的可能性)

    5)Concurrent Mode Failure
    执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足(可能是当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)便会报Concurrent Mode Failure错误,并触发Full GC。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值