内存申请过程
1、JVM会试图为相关Java对象在Eden中初始化一块内存区域;
2、当Eden空间足够时,内存申请结束。否则到下一步;
3、JVM试图释放在Eden中所有不活跃的对象(minor collection),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
4、Survivor区被用来作为Eden及old的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区;
5、当old区空间不够时,JVM会在old区进行major collection;
完全垃圾收集后,若Survivor及old区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现"Out of memory错误";
1、jvm优先分配在eden区
2、当Eden空间足够时,内存申请结束。
证明:
jvm参数设置:
-Xmx20M -Xms20M -Xmn10M -verbose:gc -XX:SurvivorRatio=8 -XX:+PrintGCDetails
其中:
-Xmx20M : 堆最大内存是20M
-Xms20M: 初始化也是20M
-Xmn10M :新生代10M,老年代10M
-verbose:gc 输出退出后的日志
-XX:SurvivorRatio=8:eden 为8M s0 s1 各1M
-XX:+PrintGCDetails:打印gc日志的详情
代码:
public class TestEden { public static void main(String[] args) { byte[] b1 = new byte[1024*1024*2]; } }
日志输出:
Heap def new generation total 9216K, used 2704K [0x03ac0000, 0x044c0000, 0x044c0000) eden space 8192K, 33% used [0x03ac0000, 0x03d64230, 0x042c0000) from space 1024K, 0% used [0x042c0000, 0x042c0000, 0x043c0000) to space 1024K, 0% used [0x043c0000, 0x043c0000, 0x044c0000) tenured generation total 10240K, used 0K [0x044c0000, 0x04ec0000, 0x04ec0000) the space 10240K, 0% used [0x044c0000, 0x044c0000, 0x044c0200, 0x04ec0000) compacting perm gen total 12288K, used 2143K [0x04ec0000, 0x05ac0000, 0x08ec0000) the space 12288K, 17% used [0x04ec0000, 0x050d7fe0, 0x050d8000, 0x05ac0000) No shared spaces configured.
通过分析main方法中申请2m的内存,内存分配到了eden区。from to tenered区都是没有被使用。
3、JVM试图释放在Eden中所有不活跃的对象(minor collection),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区;
证明:
jvm参数设置同上
代码:
public class TestEden { public static void main(String[] args) { byte[] b1 = new byte[1024*1024*9/10]; byte[] b2 = new byte[1024*1024*8*9/10]; } }
日志:
[GC [DefNew: 1250K->1024K(9216K), 0.0015682 secs] 1250K->1062K(19456K), 0.0016006 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Heap def new generation total 9216K, used 8560K [0x26ea0000, 0x278a0000, 0x278a0000) eden space 8192K, 92% used [0x26ea0000, 0x275fc308, 0x276a0000) from space 1024K, 100% used [0x277a0000, 0x278a0000, 0x278a0000) to space 1024K, 0% used [0x276a0000, 0x276a0000, 0x277a0000) tenured generation total 10240K, used 38K [0x278a0000, 0x282a0000, 0x282a0000) the space 10240K, 0% used [0x278a0000, 0x278a9920, 0x278a9a00, 0x282a0000) compacting perm gen total 12288K, used 366K [0x282a0000, 0x28ea0000, 0x2c2a0000) the space 12288K, 2% used [0x282a0000, 0x282fba28, 0x282fbc00, 0x28ea0000) ro space 8192K, 67% used [0x2c2a0000, 0x2c802f30, 0x2c803000, 0x2caa0000) rw space 12288K, 53% used [0x2caa0000, 0x2d110180, 0x2d110200, 0x2d6a0000)
分析:
程序执行逻辑 先申请了1M的内存,然后再次申请8M的内存,考虑内存本身结构会占用内存空间为了避免边界都以9/10的比例来申请。
结果:
先分配了解决1M的内存在eden区,因为再次申请接近8M的内存时,eden区不够,发生了一次young gc,1M的内存分配到了from区,接近8M的内存放在了eden区。
[GC [DefNew: 1250K->1024K(9216K), 0.0015682 secs] 1250K->1062K(19456K), 0.0016006 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
其中
9216K 为eden+from = 8M+1M=9M
19456K 为Xmx-to = 20M-1M = 19M
1250K->1024K :本次young gc 年轻代内存的变化
1250K->1062K :本次young gc 总堆内存的变化