1.Trace跟踪参数
-verbose:gc 打开GC功能
-XX:+printGC 打开GC日志在控制台显示
-XX:+PrintGCTimeStamps 打印GC发生的时间戳
-XX:+PrintGCDetails 打开GC详细信息,在程序调用结束后会打印出详细的堆内存信息,下面是在64位jdk1.7版本下使用参数:-Xmx10m -Xms10m -XX:+PrintGCDetails -XX:-UseParallelGC -XX:+UseSerialGC
Heap
def new generation total 3072K, used 2700K [0x00000000fa400000, 0x00000000fa750000, 0x00000000fa750000)
eden space 2752K, 98% used [0x00000000fa400000, 0x00000000fa6a3250, 0x00000000fa6b0000)
from space 320K, 0% used [0x00000000fa6b0000, 0x00000000fa6b0000, 0x00000000fa700000)
to space 320K, 0% used [0x00000000fa700000, 0x00000000fa700000, 0x00000000fa750000)
tenured generation total 6848K, used 0K [0x00000000fa750000, 0x00000000fae00000, 0x00000000fae00000)
the space 6848K, 0% used [0x00000000fa750000, 0x00000000fa750000, 0x00000000fa750200, 0x00000000fae00000)
compacting perm gen total 21248K, used 2560K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
the space 21248K, 12% used [0x00000000fae00000, 0x00000000fb080060, 0x00000000fb080200, 0x00000000fc2c0000)
No shared spaces configured.
同样的参数在32位jdk1.7版本下的返回结果是:
Heap 低边界 当前边界 最高边界
def new generation total 3072K, used 2013K [0x33e00000, 0x34150000, 0x34150000)
eden space 2752K, 73% used [0x33e00000, 0x33ff7788, 0x340b0000)
from space 320K, 0% used [0x340b0000, 0x340b0000, 0x34100000)
to space 320K, 0% used [0x34100000, 0x34100000, 0x34150000)
tenured generation total 6848K, used 379K [0x34150000, 0x34800000, 0x34800000)
the space 6848K, 5% used [0x34150000, 0x341aed10, 0x341aee00, 0x34800000)
compacting perm gen total 12288K, used 179K [0x34800000, 0x35400000, 0x38800000)
the space 12288K, 1% used [0x34800000, 0x3482cc20, 0x3482ce00, 0x35400000)
ro space 10240K, 44% used [0x38800000, 0x38c7d3a8, 0x38c7d400, 0x39200000)
rw space 12288K, 52% used [0x39200000, 0x39849a18, 0x39849c00, 0x39e00000)
def new generation:指新生代,新创建的对象都在这部分内存中。
eden space:伊甸园,通过new创建的对象首先存放在这里。
from space和to space是幸存区,从伊甸园创建的对象在GC的时候首先会分配的幸存区,如果幸存区放不下则会放到老年区,幸存区两部分的内存分配大小是一样的。
tenured generation:老年代,对于长时间被引用的对象会从新生代转移到老年代中,这里的对象存在的时间一般都比较长。
compacting perm gen:持久代,这块内存区域32位和64位结果不一样,32位jdk默认开启了永久区的内存共享,所以ro space和rw space有有值,且持久代的内存使用比较少,只有179k,只占1%。这可能也是为什么有些java程序在64位jdk下占用的内容比32位jdk下多的原因。
中括号中的三个数分别是低边界:内存中分配区域的最低位置,当前边界:现在已经分配的内存地址,最高边界:可以被分配的最高内存地址。如果当前边界和最高边界相同,则内存已经分配完毕,不能够再进行扩展,反之这可以进行进一步扩展。新生代(def new generation)被分配的内存大小计算公式:
(0x34150000-0x33e00000)/1024/1024=3392k
这个大小等于eden space+from space+to space,新生代的可用空间是3072k,并不等于分配的总内存3392k,这之间的差距就是to space的内存空间没有包含在内,这个是由GC的算法决定的。
-Xloggc:log/gc.log: 指定GC log的位置以文件的形式输出,帮助开发人员分析问题。
-XX:+PringHeapAtGC:每一次GC后都打印堆的信息,会将GC前和GC后的堆的信息都打印出来。GC后一般会将eden的内存区域清空,将该部分的对象转移到老年代里面。
-XX:+TraceClassLoading:监控类的加载,每个类的加载监控。比如要做一些跟踪调试的时候可看到哪些类加载进来了。
-XX:+PrintClassHisgogram:打印类的直方图。对着控制台按下Ctrl+Break后,会打印类的统计信息,可以看出每个类的数量、总大小以及类的名称,对于查找内存溢出比较有用。
2.堆的分配参数:
-Xmx -Xms:指定最大堆和最小堆,指定jvm所使用的最大和最小堆内存大小。jvm会尽可能的维持在最小堆中运行程序。
-Xmn:设置新生代的大小的绝对值
-XX:NewRatio:设置新生代(eden+2*s)和老年代(不包含永久区)的比值。比如设置为4,表示新生代:老年代=1:4,则新生代占堆的1/5。
-XX:SurvivorRatio:设置两个Survivor区和eden的比,比如设置为8,表示两个Survivor:eden=2:8,即一个Survivor占新生代的1/10.
-XX:+HeapDumpOnOutOfMemoryError:将系统发生OOM时导出堆到文件中,方便查找问题的原因。
-XX:+HeapDumpPath:导出OOM的路径。
public class TestDump {
public static void main(String[] args) {
Vector v=new Vector();
for(int i=0;i<25;i++)
v.add(new byte[1*1024*1024]);
}
}
对于上面的代码使用参数-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump即可得到jvm在内存溢出时的dump文件,dump文件的大小和分配的堆内存大小是一样的。使用Eclipse的 Memory Analyzer 插件可以打开这个dump文件进行分析。
-XX:OnOutOfMemoryError:在OOM是执行一个脚本。可以在OOM的时候,发送邮件或者重启程序。如果我们想在发送OOM的时候做一些其他的分析,比如输出线程的dump文件,就可以使用这个参数。
根据实际情况调整新生代和幸存代的大小,官方推荐的新生代占堆的3/8,幸存区(Survivor)占新生代的1/10.在生产环境中一般OOM的错误无法在开发环境重现,所以记得dum出堆的信息,确保可以排查现场问题。
3.永久区分配参数:
-XX:PermSize -XX:MaxPermSize:设置永久区的初始空间和最大空间。他们表示,这个系统可以容纳多少个类型。永久区也是方法区,保存一些class信息,包括类的常量池,字段和方法信息,以及方法字节码,一般系统分配几百M即可。
如果堆空间没有用完也抛出了OOM,则有可能是永久区的溢出。
4.栈的分配参数:
-Xss:栈空间通常只有几百K,决定了函数调用的深度,如果系统中存在递归调用,如果栈空间设置的很小,则很有可能出现栈溢出。每个线程都有独立的栈空间,所以如果系统中需要多个线程来运行,则栈的空间不能分配太大。程序中的局部变量、参数以及函数调用都分配在栈上。减少局部变量的使用也可以减少栈空间的使用,可以让函数多调用几次。
栈溢出会报异常:java.lang.StackOverflowError,如果看到这个异常就可能是函数调用太深或者局部变量太多导致的栈内存溢出。