JVM常用配置参数
总阅读次
JVM常用配置参数
本文将介绍 Trace跟踪参数 、堆的分配参数 、栈的分配参数
运行环境
|
|
Trace跟踪参数
打印GC的简要信息
- -verbose:gc
- -XX:+PrintGC
打印如下信息
|
|
ps:这里使用的Java代码是前文中使用的OnStackTest
类的代码
打印GC的详细信息
- -XX:+PrintGCDetails
- 打印GC详细信息
- -XX:+PrintGCTimeStamps
- 打印GC发生的时间戳
命令如下:
java -server -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+PrintGCTimeStamps OnStackTest
打印结果如下,执行完代码前会打印堆信息:
|
|
ps:这里使用的Java代码是前文中使用的OnStackTest
类的代码
指定GC log的存放位置
- -Xloggc:log/gc.log
具体命令如下:
java -server -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/home/yinqi/apps/gc.log OnStackTest
将在指定目录生成一个gc.log文件
每次GC后,都打印堆信息
- -XX:+PrintHeapAtGC
执行命令如下:
java -server -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintHeapAtGC OnStackTest
打印结果如下:
|
|
ps:这里使用的Java代码是前文中使用的OnStackTest
类的代码
监控类的加载
- -XX:+TraceClassLoading
通过该参数可以追踪类的加载
|
|
堆的分配参数
- -Xmx -Xms 指定堆的最大值和最小值
|
|
通过命令 java -Xmx20m -Xms5m TestDump
命令运行该类
|
|
通过添加使用内存
|
|
通过命令 java -Xmx20m -Xms5m TestDump
结果如下,空闲内存少了1M:
|
|
再添加内存
|
|
通过命令 java -Xmx20m -Xms5m TestDump
结果如下,总内存变多了:
|
|
这也表明,JVM尽量维护最小的堆内存
设置新生代的大小
- -Xmn 设置新生代大小
- -XX:NewRatio 新生代(eden+2*s)和老年代的比值 例如 4 表示新生代:老年代=1:4,即年轻代占堆的1/5
- -XX:SurvivorRatio 设置两个Survivor区和eden区的比;例如 8 表示两个Survivor:eden=2:8,即一个Survivor占年轻代的1/10
创建如下代码
|
|
执行 java -Xmx20m -Xms20m -Xmn1m -XX:+UseSerialGC -XX:+PrintGCDetails TestDump2
命令,新生代设置为1m
|
|
通过查看堆的信息发现没有发生GC,并且都分配在老年代。因为新生代过小,将所有数据都放在老年代
还是上面的代码,通过该命令运行 java -Xmx20m -Xms20m -Xmn15m -XX:+UseSerialGC -XX:+PrintGCDetails TestDump2
,设置新生代的大小为15m
|
|
还是没有发生GC,全部分配在eden区。因为新生代分配了15m,eden区占了12m,可以放下总共10m的数据,所以都分配在eden区
还是上面的代码,通过该命令运行 java -Xmx20m -Xms20m -Xmn6m -XX:+UseSerialGC -XX:+PrintGCDetails TestDump2
,设置新生代的大小为6m
|
|
进行两次新生代的GC,from to 太小需要使用老年代。第一次GC回收了差不多3m,第二次GC也差不多回收了3m;新生代总共使用了差不多2m,老年代也使用了差不多2m
还是上面的代码,通过该命令运行 java -Xmx20m -Xms20m -Xmn6m -XX:SurvivorRatio=2 -XX:+UseSerialGC -XX:+PrintGCDetails TestDump2
,增大s0和s1的大小
|
|
进行了4次GC,并且没有使用老年代的空间
还是上面的代码,通过该命令运行 java -Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=2 -XX:+UseSerialGC -XX:+PrintGCDetails TestDump2
,增加新生代的大小
|
|
增加新生代的大小为整个堆的1/2,s0+s1总共为5m,eden区总共为5m,老年代总共10m。发生了2次GC,没有使用老年代
还是上面的代码,通过该命令运行 java -Xmx20m -Xms20m -XX:NewRatio=1 -XX:SurvivorRatio=3 -XX:+UseSerialGC -XX:+PrintGCDetails TestDump2
,减少了s0和s1的大小
|
|
通过减少s0和s1的大小达了减少GC次数的效果
OOM时导出堆到文件
- -XX:+HeapDumpOnOutOfMemoryError 内存溢出时导出当前堆到文件
- -XX:HeapDumpPath 导出OOM的路径
通过下面这段代码进行测试
|
|
执行如下命令
|
|
导出的文件大小和堆的最大值的大小一样大,通过 MemoryAnalyzer 工具分析该dump文件,如下图
- -XX:OnOutOfMemoryError 在OOM时,执行一个脚本,该脚本可以执行很多事情比如重启应用,发送脚本
|
|
堆的分配参数总结
- 根据实际情况调整新生代和幸存代的大小
- 官方推荐新生代占堆的3/8
- 幸存代占新生代的1/10
- 在OOM时,记得Dump出堆,确保可以排查现场问题
永久区分配参数
- -XX:PermSize 设置永久区的初始空间
- -XX:MaxPermSize 设置永久区的最大空间
- 他们表示,一个系统可以容纳多少个类型
栈大小分配
-Xss
- 通常只有几百K
- 决定函数调用的深度
- 每个线程都有独立的栈空间
- 局部变量、参数都分配在栈上
通过如下代码测试栈的分配
12345678910111213141516public class TestStackDeep {private static int count=0;public static void recursion(long a,long b,long c){long e=1,f=2,g=3,h=4,i=5,k=6,q=7,x=8,y=9,z=10;count++;recursion(a,b,c);}public static void main(String args[]){try{recursion(0L,0L,0L);}catch(Throwable e){System.out.println("deep of calling = "+count);e.printStackTrace();}}}通过如下命令运行:
java -Xss160k TestStackDeep
12deep of calling = 221java.lang.StackOverflowError通过如下命令运行:
java -Xss256k TestStackDeep
12deep of calling = 577java.lang.StackOverflowError通过上面的代码可以发现,增加栈空间的大小可以增加递归函数的调用次数