不同的jvm参数可以在gc信息中显示出不同的内容,我们先来学习以下简单的gc信息.
开启-XX:+PrintGCDetails参数,运行java程序查看gc信息
[GC (System.gc()) [PSYoungGen: 523K->368K(4608K)] 523K->376K(15872K(可用堆大小)), 0.0014747 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System.gc()) [PSYoungGen: 368K->0K(4608K)] [ParOldGen: 8K->297K(11264K)] 376K->297K(15872K), [Metaspace: 2643K->2643K(1056768K)], 0.0043307 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Heap PSYoungGen(新生代大小) total 4608K, used 0K [0x00000007bfb00000, 0x00000007c0000000, 0x00000007c0000000] (三个16进制数据分别代表下界,当前上界,上界) 上界-下届= 堆空间的最大值; 当前上界-下界=已为虚拟机分配的空间;上界=当前上界 说明已经没有扩展空间了 eden space 4096K, 0% used [0x00000007bfb00000,0x00000007bfb00388,0x00000007bff00000) from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000) to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000] ParOldGen (老年代大小) total 11264K, used 297K [0x00000007bf000000, 0x00000007bfb00000, 0x00000007bfb00000) object space 11264K, 2% used [0x00000007bf000000,0x00000007bf04a698,0x00000007bfb00000] Metaspace ((方法区大小)) used 2649K, capacity 4486K, committed 4864K, reserved 1056768K class space used 287K, capacity 386K, committed 512K, reserved 1048576K
GC 信息的相关参数
-XX:+PrintHeapAtGC,可以查看GC回收前后的堆信息 -XX:+PrintGCTimeStamps 打印GC发生的时间戳,相对于虚拟机的启动时间 -XX:+PrintReferenceGc 可以查看软饮用,弱引用,虚引用和Finallize队列 -XLoggc:log/gc.log 指定gc日志以文件形式输出 -verbose:gc 开启gc跟踪 -verbose:class 跟踪类的加载和卸载等价于-XX:+TraceClassLoading和 -XX:+TraceClassUnloading -XX:+PrintCommandLineFlags可以打印出虚拟机的显式和隐式参数
新生代老生代参数测试
-Xms:最小堆内存(初始分配的) -Xmx:最大堆内存(超过这个就会内存溢出) -Xmn:新生代的大小 -XX:SurvivorRatio 设置eden空间和from/to空间的比例大小 -XX:NewRatio=老年代/新生代
jvm参数:-Xms15m -Xmx15m –Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails public static void main(String[] args) throws InterruptedException { byte[] b = null; for(inti = 0 ;i< 10 ;i++){ b = newbyte[1*1024*1024]; } }
SurvivorRatio = eden/from =2;
可用的=eden+from
总共的=eden+from+to
由于eden只有512k,不足以分配1m的空间,所以所有的都分配在老年代
[GC (Allocation Failure) [PSYoungGen: 512K->432K(1024K)] 512K->440K(15872K), 0.0014905 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Heap PSYoungGen total 1024K, used 457K [0x00000007bfe80000, 0x00000007c0000000, 0x00000007c0000000) eden space 512K, 5% used [0x00000007bfe80000,0x00000007bfe86798,0x00000007bff00000) from space 512K, 84% used [0x00000007bff00000,0x00000007bff6c010,0x00000007bff80000) to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000) ParOldGen total 14848K, used 10248K [0x00000007bf000000, 0x00000007bfe80000, 0x00000007bfe80000) object space 14848K, 69% used [0x00000007bf000000,0x00000007bfa020a0,0x00000007bfe80000) Metaspace used 2645K, capacity 4486K, committed 4864K, reserved 1056768K class space used 286K, capacity 386K, committed 512K, reserved 1048576K
-Xms20m -Xmx20m -Xmn6m -XX:SurvivorRatio=2 -XX:+PrintGCDetails
如果eden有足够的空间,所有的内存都会在eden分配
-Xms20m -Xmx20m -XX:NewRatio=2 -XX:+PrintGCDetails
这样新生代为6m 老年代为13m,from空间为600k,新生代回收的时候需要老年代进行空间担保.
堆溢出的处理
如果堆空间不足,就会outofmemory:Java Heap Space.使用参数-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/zcf1/Downloads/test.dump
导出发生内存溢出时,整个堆的信息.“-XX:OutOfMemoryError=脚本路径 %p”
脚本内容(进程信息)
…bin/jstack –F %l > 路径/a.txt
直接内存配置
-XX:MaxDirectMemorySize,默认是-Xmx,达到MaxDirectMemorySize时候就会触发垃圾回收。
直接内存的优势在于读写速度快于堆内存,下面程序用来测试直接内存和堆内存性能的比较.
public class AccessDirectBuffer { public static void directAccess(){ long begin = System.currentTimeMillis(); ByteBuffer b = ByteBuffer.allocateDirect(500); for(int i = 0 ;i< 10000000;i++){ for(int j =0 ;j< 99;j++){ b.putInt(j); } b.flip(); for(int j =0 ;j< 99;j++){ b.getInt(); } b.clear(); } long end = System.currentTimeMillis(); System.out.println("Direct:"+(end-begin)); } public static void bufferAccess(){ long begin = System.currentTimeMillis(); ByteBuffer b = ByteBuffer.allocate(500); for(int i = 0 ;i< 10000000;i++){ for(int j =0 ;j< 99;j++){ b.putInt(j); } b.flip(); for(int j =0 ;j< 99;j++){ b.getInt(); } b.clear(); } long end = System.currentTimeMillis(); System.out.println("buffer:"+(end-begin)); } public static void main(String[] args) { bufferAccess(); directAccess(); } }