深入理解java虚拟机(七):java垃圾收集分析总结

 2019-12-22 10:59  阅读(800)
文章分类:JVM

一、垃圾回收触发条件

1、Minor gc触发条件

当新生代空间不足时会主动触发Minor gc,并且自动扩容(可通过控制使新生代直接处于最大内存空间,避免自动扩容和垃圾收集)。

2、Full gc触发条件

和新生代一样,当老年代空间不足时会触发Full gc,并且自动扩容;另外当在代码中调用**System.gc()**时也会触发Full gc。 可通过参数-XX:+DisableExplicitGC 控制使System.gc()失效。

3、永久待触发条件

类似上面,当永久待空间不足时,会发出Full gc,可通过控制PermSize=MaxPermSize 避免自动扩容和垃圾回收。另外可通过参数**-Xnoclassgc 来控制虚拟机不对类(永久待类对象)进行回收。**

二、Runtime.exec创建新进程(内存叠加)占用外部内存

java虚拟机执行Runtime.exec 的过程是:首先克隆一个和当前虚拟机拥有一样环境变量的进程,再用这个心的进程区执行外部命令,最后再退出这个进程
如果频繁执行,系统的消耗会很大,不仅是cpu还有内存。
另外这个时候要注意了,在采集java程序的内存时,一定要注意有java程序通过Runtime.exec创建的新进程所占用的内存,按理来说,java创建的新进程所占用的内存也应该归属于这个java程序的内存。
例:下面是在redhat下面用java程序通过Runtime.exec执行shell脚本。

import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.util.Date;

    public class TestSleep {

            public static void main(String[] args) {
                    System.out.println("being sleep"+new Date().toLocaleString());
                    try
                    {
                    Runtime rt = Runtime.getRuntime();
                    Process proc = rt.exec("/home/boco/script/sleep.sh");
                    InputStream stdin = proc.getInputStream();
                    InputStreamReader isr = new InputStreamReader(stdin);
                    BufferedReader br = new BufferedReader(isr);
                    String line = null;
                    System.out.println("output");
                    while ( (line = br.readLine()) != null)
                    System.out.println(line);
                    System.out.println("");
                    int exitVal = proc.waitFor();
                    System.out.println("Process exitValue: " + exitVal);
                    } catch (Throwable t)
                    {
                    t.printStackTrace();
                    }

                    System.out.println("end sleep"+new Date().toLocaleString());
            }
    }

shell脚本内容:

#!/bin/bash
    echo "begin"
    sleep 10
    echo "end"

执行结果:

2019120001454\_1.png
可以看出有java进程产生了一个子进程,即shell脚本,而这个shell脚本又产生了一个子进程,即sleep。

三、类加载-字节码验证时间

类加载时间虚拟机加载类所耗掉的总时间
字节码验证会耗掉一部分时间,在保证字节码是安全的情况下,可以通过参数 -Xverify:none禁止掉字节码验证过程。

2019120001454\_2.png

四、编译时间

编译时间指虚拟机的JIT编译器(Just in time Compiler)编译热点代码(Hot Spot Code)的耗时

我们知道java语言为了实现跨平台的特性, java代码编译出来后形成的class文件中存储的是字节码(ByteCode),虚拟机通过解释方式执行字节码命令,比起c语言的编译执行速度要慢不少。 不过在java1.2后,虚拟机内置了2个运行期间编译器(代号为C1和C2,C1在client模式下启用,C2在server模式下启用),如果一个java方法被调用数次到一定程度就会被判定为热代码交个JIT编译器编译为本地代码, 提高运行速度,这就是hotspot虚拟机名字的由来
编译时间总长即为编译热代码所消耗的时间总和。

五、垃圾收集打印参数

-XX:+PrintGCApplicationStoppedTime 参数打印gc停顿时间
-XX:+PrintGCDateStamps 参数打印gc时间戳,系统时间
-XX:+PrintGCTimeStamps 参数打印gc时间,相对于jvm启动时间
-Xloggc:gclog.log 设置gc日志文件
-XX:+PrintReferenceGC 打印gc引用
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中断的执行时间
-XX:+PrintHeapAtGC 打印GC前后的详细堆栈信息

例:

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -Xloggc:gclog.log -XX:+PrintGCApplicationConcurrentTime -XX:+PrintHeapAtGC

输出gclog.log:

Application time: 0.0055586 seconds {Heap before GC invocations=0 (full 0):
     def new generation   total 9216K, used 6487K [0x32750000, 0x33150000, 0x33150000)
      eden space 8192K,  79% used [0x32750000, 0x32da5fd0, 0x32f50000)
      from space 1024K,   0% used [0x32f50000, 0x32f50000, 0x33050000)
      to   space 1024K,   0% used [0x33050000, 0x33050000, 0x33150000)
     tenured generation   total 10240K, used 0K [0x33150000, 0x33b50000, 0x33b50000)
       the space 10240K,   0% used [0x33150000, 0x33150000, 0x33150200, 0x33b50000)
     compacting perm gen  total 12288K, used 377K [0x33b50000, 0x34750000, 0x37b50000)
       the space 12288K,   3% used [0x33b50000, 0x33bae748, 0x33bae800, 0x34750000)
        ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
        rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
    2014-02-26T15:44:05.625+0800: 0.049: [GC 0.049: [DefNew: 6487K->151K(9216K), 0.0040768 secs] 6487K->6295K(19456K), 0.0041381 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    Heap after GC invocations=1 (full 0):
     def new generation   total 9216K, used 151K [0x32750000, 0x33150000, 0x33150000)
      eden space 8192K,   0% used [0x32750000, 0x32750000, 0x32f50000)
      from space 1024K,  14% used [0x33050000, 0x33075ee8, 0x33150000)
      to   space 1024K,   0% used [0x32f50000, 0x32f50000, 0x33050000)
     tenured generation   total 10240K, used 6144K [0x33150000, 0x33b50000, 0x33b50000)
    &bsp;  the space 10240K,  60% used [0x33150000, 0x33750030, 0x33750200, 0x33b50000)
     compacting perm gen  total 12288K, used 377K [0x33b50000, 0x34750000, 0x37b50000)
       the space 12288K,   3% used [0x33b50000, 0x33bae748, 0x33bae800, 0x34750000)
        ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
        rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
    }
    Total time for which application threads were stopped: 0.0043639 seconds
    Heap
     def new generation   total 9216K, used 4575K [0x32750000, 0x33150000, 0x33150000)
      eden space 8192K,  54% used [0x32750000, 0x32ba1fa8, 0x32f50000)
      from space 1024K,  14% used [0x33050000, 0x33075ee8, 0x33150000)
      to   space 1024K,   0% used [0x32f50000, 0x32f50000, 0x33050000)
     tenured generation   total 10240K, used 6144K [0x33150000, 0x33b50000, 0x33b50000)
       the space 10240K,  60% used [0x33150000, 0x33750030, 0x33750200, 0x33b50000)
     compacting perm gen  total 12288K, used 377K [0x33b50000, 0x34750000, 0x37b50000)
       the space 12288K,   3% used [0x33b50000, 0x33bae748, 0x33bae800, 0x34750000)
        ro space 10240K,  55% used [0x37b50000, 0x380d1140, 0x380d1200, 0x38550000)
        rw space 12288K,  55% used [0x38550000, 0x38bf44c8, 0x38bf4600, 0x39150000)
    Application time: 0.0007510 seconds
点赞(1)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 深入理解java虚拟机(七):java垃圾收集分析总结

相关推荐