转载

jvm-内存申请过程分析

内存申请过程

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 总堆内存的变化

正文到此结束
Loading...