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

时间:2023-01-02 08:36:26

深入理解java虚拟机(一):java内存区域(内存结构划分)
深入理解java虚拟机(二):java内存溢出实战 
深入理解java虚拟机(三):String.intern()-字符串常量池
深入理解java虚拟机(四):对象存活判定算法和垃圾收集算法
深入理解java虚拟机(五):hotspot垃圾收集算法实现 
深入理解java虚拟机(六):java垃圾收集分析实战(内存分配与回收策略)

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

深入理解java虚拟机(八):java内存分析工具-MAT和OQL

一、垃圾回收触发条件

  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"


执行结果:

[置顶]        深入理解java虚拟机(七):java垃圾收集分析总结
 可以看出有java进程产生了一个子进程,即shell脚本,而这个shell脚本又产生了一个子进程,即sleep。

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

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

 

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

 

四、编译时间

编译时间指虚拟机的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)
   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