JVM垃圾回收与调优详解 下载本文

1.JVM内存分配与回收

1.1 对象优先在Eden区分配

大多数情况下,对象在新生代中 Eden 区分配。当 Eden 区没有足够空间进行分配时,虚拟机将发起一次Minor GC。我们来进行实际测试一下。 在测试之前我们先来看看 Minor Gc和Full GC 有什么不同呢?

? 新生代GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC非

常频繁,回收速度一般也比较快。

? 老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major

GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC的慢10倍以上。 测试:

通过以下方式运行:

添加的参数: -XX:+PrintGCDetails

运行结果:

从上图我们可以看出eden区内存几乎已经被分配完全(即使程序什么也不做,新生代也会使用至少2000多k内存)。假如我们再为allocation2分配内存会出现什么情况呢?

简单解释一下为什么会出现这种情况: 因为给allocation2分配内存的时候eden区内存几乎已经被分配完了,我们刚刚讲了当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC.GC期间虚拟机又发现allocation1无法存入Survior空间,所以只好通过 分配担保机制 把新生代的对象提前转移到老年代中去,老年代上的空间足够存放allocation1,所以不会出现Full GC。执

行Minor GC后,后面分配的对象如果能够存在eden区的话,还是会在eden区分配内存。可以执行如下代码验证:

1.2 大对象直接进入老年代

大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。 为什么要这样呢?

为了避免为大对象分配内存时由于分配担保机制带来的复制而降低效率。

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

既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别那些对象应放在新生代,那些对象应放在老年代中。为了做到这一点,虚拟机给每个对象一个对象年龄(Age)计数器。

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