JVM的垃圾收集算法和实例分析

JVM内存主要组成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1. 方法区 Method Area

2.虚拟机栈 VM Stack

3.本地方法栈 Native Method Stack

4.堆Heap

	堆空间=新生代[eden+from_survivor+to_survivor]+tenured老年代+perm永久代

5.程序计数器 Program Counter Register

6.运行时常量池

7.直接内存

垃圾收集算法

1.复制算法

1
2
3
4
5
6
新生代默认垃圾收集算法:新生代堆分为eden+from_survivor+to_survivor, survivor比例=8

当发生GC时,
1.将存活对象复制到to_survivor,然后存活对象大于[to_survivor]/2,则直接移动到老年代;
2.将存活对象复制到to_survivor,如果to_survivor空间不够且老年代的可用空间大于存活对象的大小,就把存活对象复制到老年代;
3.将存活对象复制到to_survivor, 如果to_survivor空间不够且老年代的可用空间小于存活对象的大小,则不移动新生代对象,直接将需要分配的内存对象分配到老年代;

2.标记-整理(Mark-compact)算法

1
老年代默认牢记收集算法:标记可回收的对象和存活对象,然后让存活对象全部都向一端移动,然后直接清除掉端边界以外的内存。

3.标记-清除(Mark-Sweep)算法

1
标记可回收对象和存活对象,然后直接清除可回收对象,这样可能会导致内存不连续。

GC回收分析

第一种情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package gc;

public class TestAllocation {
  private static final int _1MB = 1024 * 1024;
  /**
   * VM参数  -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
   * 
   * eden:8MB
   * 1-survivor: 1MB
   * 
   * tenured: 10MB
   * 
   * 
   */
  
  public static void main(String[] args) {
    byte[] allocation1, allocation2, allocation3, allocation4,allocation5, allocation6, allocation7;
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB];
    System.out.println("1.Minor GC, 当eden+[from-survivor]空闲空间小于2MB时,则发生minor GC,实行复制算法,无法全部移到[to-survivor],则全部移到tenured老年代");
    allocation4 = new byte[2 * _1MB];
    allocation5 = new byte[2 * _1MB];
    allocation6 = new byte[2 * _1MB];
    System.out.println("2.Full GC,老年代的可用空间大于当此时新生代所有的对象或者历次晋升平均大小,则会进行Minor GC,否则要执行Major GC[Full GC]");
    allocation7 = new byte[2 * _1MB];
    
  }

}

打印结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.Minor GC, 当eden+[from-survivor]空闲空间小于2MB时,则发生minor GC,实行复制算法,无法全部移到[to-survivor],则全部移到tenured老年代
[GC [DefNew: 6816K->485K(9216K), 0.0045302 secs] 6816K->6629K(19456K), 0.0045597 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
2.Full GC,老年代的可用空间大于当此时新生代所有的对象或者历次晋升平均大小,则会进行Minor GC,否则要执行Major GC[Full GC]
[GC [DefNew: 7047K->7047K(9216K), 0.0000099 secs][Tenured: 6144K->8192K(10240K), 0.0044891 secs] 13191K->12773K(19456K), [Perm : 2556K->2556K(21248K)], 0.0045369 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 6711K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
  eden space 8192K,  81% used [0x00000000f9a00000, 0x00000000fa08df68, 0x00000000fa200000)
  from space 1024K,   0% used [0x00000000fa300000, 0x00000000fa300000, 0x00000000fa400000)
  to   space 1024K,   0% used [0x00000000fa200000, 0x00000000fa200000, 0x00000000fa300000)
 tenured generation   total 10240K, used 8192K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
   the space 10240K,  80% used [0x00000000fa400000, 0x00000000fac00040, 0x00000000fac00200, 0x00000000fae00000)
 compacting perm gen  total 21248K, used 2563K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
   the space 21248K,  12% used [0x00000000fae00000, 0x00000000fb080f90, 0x00000000fb081000, 0x00000000fc2c0000)
No shared spaces configured.

第二种情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package gc;

public class TestAllocation2 {
  private static final int _1MB = 1024 * 1024;
  /**
   * VM参数  -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC
   * 
   * eden:8MB
   * 1-survivor: 1MB
   * 
   * tenured: 10MB 
   */
  
  public static void main(String[] args) {
    byte[] allocation1, allocation2, allocation3, allocation4,allocation5, allocation6, allocation7;
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB];
    System.out.println("1.Minor GC, 当eden+[from-survivor]空闲空间小于2MB时,则发生minor GC,实行复制算法,无法全部移到[to-survivor],则全部移到tenured老年代");
    allocation4 = new byte[2 * _1MB];
    System.out.println("2.Minor GC,因为老年代的可用空间3M多大于当此时新生代所有的对象2M多,则进行Minor GC");
    allocation7 = new byte[6 * _1MB];
    
  }

}

打印结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
[GC [DefNew: 6816K->485K(9216K), 0.0041725 secs] 6816K->6629K(19456K), 0.0042027 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2.Full GC,老年代的可用空间大于当此时新生代所有的对象或者历次晋升平均大小,则会进行Minor GC,否则要执行Major GC[Full GC]
[GC [DefNew: 2787K->486K(9216K), 0.0021193 secs] 8931K->8678K(19456K), 0.0021379 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 6957K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
  eden space 8192K,  79% used [0x00000000f9a00000, 0x00000000fa051f90, 0x00000000fa200000)
  from space 1024K,  47% used [0x00000000fa200000, 0x00000000fa279860, 0x00000000fa300000)
  to   space 1024K,   0% used [0x00000000fa300000, 0x00000000fa300000, 0x00000000fa400000)
 tenured generation   total 10240K, used 8192K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
   the space 10240K,  80% used [0x00000000fa400000, 0x00000000fac00040, 0x00000000fac00200, 0x00000000fae00000)
 compacting perm gen  total 21248K, used 2563K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
   the space 21248K,  12% used [0x00000000fae00000, 0x00000000fb080f60, 0x00000000fb081000, 0x00000000fc2c0000)
No shared spaces configured.


版权声明:自由转载-非商用-非衍生-保持署名 lonpo 本文永久链接: http://lonpo.github.io/jvm/JVM-GC/