JavaJVM垃圾回收机制入门

Java程序员进阶三条必经之路:数据库、虚拟机、异步通信。

前言

数据库是我们会普遍青睐的一个世界,异步通信一般用不到,虚拟机在大多数时候不会出题目,常被人忽略,所以我打算先读书虚拟机,从零单排Java高性能问题。

堆内存存储结构

Paste_Image.png

Java6是以年代来计划内存的,而Java7的G1收集器则相反,这里以Java6为准。
SurSamsungr1和Sur金立r2是一样大的,必有一个一味为空,容量小于Eden。

垃圾回收机制

少壮代采用复制算法,当回收时,将艾登(Eden)和SurHTCr中还存世的靶子一次性地复制到此外一块Sur中兴r上,然后清理掉Eden和刚刚用过的SurHTCr空间。每举行一回Minor
GC(年轻代回收),对象的年华就扩充1岁(起始为0),当年龄扩充到一定水准(默认15岁),就会被移到老年代。老年代的回收算法因篇幅有限在此略过。

从《深刻通晓Java虚拟机》第二版93页上抄一个例子来做个示范:

package com.jiuyan.mountain.jvm;

public class Test {

  private static final int MB = 1024 * 1024;

  public static void main(String[] args) {
    byte[] bytes1, bytes2, bytes3, bytes4;
    bytes1 = new byte[2 * MB];
    bytes2 = new byte[2 * MB];
    bytes3 = new byte[2 * MB];
    bytes4 = new byte[4 * MB];
  }
}

命令行执行:

java -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 com/jiuyan/mountain/jvm/Test

参数解释:

  1. Xms20M:初始堆20M
  2. Xmx20M:最大堆20M
  3. Xmn10M:年轻代10M
  4. -XX:+PrintGCDetails:打印GC详细信息
  5. -XX:Sur一加rRatio=8:艾登(Eden)和一个SurOne plusr的上空比例是8:1。

输出:

Heap
 PSYoungGen      total 9216K, used 6799K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 83% used [0x00000000ff600000,0x00000000ffca3f28,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff000010,0x00000000ff600000)
 PSPermGen       total 21504K, used 2751K [0x00000000f4600000, 0x00000000f5b00000, 0x00000000fec00000)
  object space 21504K, 12% used [0x00000000f4600000,0x00000000f48afc08,0x00000000f5b00000)

JVM没有开展垃圾回收,byte1、byte2、byte3、byte4总共10M内存,而青春代只有9M内存,不应该啊。结果艾登有6M内存(bytes1,bytes2,bytes3),老年代有4M内存(bytes4),表明bytes4间接被分配到了老年代,因为在Sur华为r空间中当相同年龄有所目的大小的总额大于SurSamsungr空间的一半,年龄大于或等于该年龄的对象就可以一贯进去老年代。

这就是说我就调用System.gc()来积极触发两次GC。
输出:

[GC-- [PSYoungGen: 6635K->6635K(9216K)] 10731K->14827K(19456K), 0.0035280 secs] [Times: user=0.00 sys=0.01, real=0.00 secs] 
[Full GC [PSYoungGen: 6635K->2275K(9216K)] [ParOldGen: 8192K->8192K(10240K)] 14827K->10467K(19456K) [PSPermGen: 2743K->2742K(21504K)], 0.0079080 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 9216K, used 2441K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 29% used [0x00000000ff600000,0x00000000ff8624d8,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 8192K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 80% used [0x00000000fec00000,0x00000000ff400030,0x00000000ff600000)
 PSPermGen       total 21504K, used 2750K [0x00000000f4600000, 0x00000000f5b00000, 0x00000000fec00000)
  object space 21504K, 12% used [0x00000000f4600000,0x00000000f48af8d0,0x00000000f5b00000)

日志分析:

  1. GC和Full
    GC表达了本次垃圾收集的暂停类型,而不是用来区别年轻代依旧老年代的。即使有“Full”,表达这次GC发生了STW(Stop-The-World)。
  2. PSYoungGen是使用Parallel
    Scavenge收集器的年轻代,ParOldGen是应用Parallel
    Old收集器的老年代,Tenured是利用Serial Old收集器的老年代。
  3. [PSYoungGen:
    6635K->6635K(9216K)]代表GC二零一七年轻代占用内存6M,GC后占用内存6M,内存区域总容量9M。10731K->14827K(19456K)表示GC前堆占用内存10M,GC后占用内存14M,堆总容量20M。
  4. GC过程是把年轻代中的4M内存复制到了老年代,所以才会出现10731K->14827K(19456K),Full
    GC过程是把青春代中的4M内存回收掉,所以才会冒出PSYoungGen:
    6635K->2275K(9216K)。

相关文章