JVM内存分配和回收策略

来源:互联网 发布:ehshig软件 编辑:程序博客网 时间:2024/05/20 11:23

1、对象优先在Eden分配

大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够的空间进行分配的时候,JVM就会发动一次Minor GC。

关于Minor GC和Full GC:

新生代GC(Minor GC):发生在新生代的垃圾回收动作,由于java大多数对象都是朝生夕灭,因此Minor GC很频繁,回收速度也很快。

老年代GC(Major GC/Full GC):发生在老年代的GC,出现了Major GC,经常至少伴随一次Minor GC(不是绝对的,但是是经常)。Major GC速度一般会比Minor GC慢10倍以上。


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

所谓的大对象就是需要大量连续内存空间的Java对象,最典型的大对象就是很长很长的字符串和数组。大对象对于虚拟机的内存分配来说是一个坏消息,然而比这更糟糕的是遇到一群朝生夕灭的大对象,写程序时一定要避免。如果经常出现大对象容易导致内存还有不少空间就必须提前GC来获得足够的连续空间来安放大对象。


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

JVM给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并且经过第一次Minor GC后仍然存活并且能够被Survivor容纳的话,就会被移动到Survivor空间,然后对象年龄设为1,从此以后每熬过一次Minor GC,对象年龄就加1,当年龄增加到一定程度(默认15),就会进入老年代。


4、动态对象年龄判定

JVM不是永远要求对象的年龄必须达到相应阈值才能进入老年代。当Survivor空间的所有相同年龄的对象大小总和大于Survivor空间的一半,年龄大于等于该年龄的对象就可以直接进入老年代,无需等到相应阈值。


5、空间分配担保(Full GC发生条件)

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

虽然当HandlePromotionFailure设置为true的时候会出现担保失败,就需要重新发起一次Full GC,但是大部分情况还是将HandlePromotionFailure设置为true,避免Full GC过于频繁。