之前被问到jvm性能监控方面的问题,花时间对jvm相关的参数进行了一些研究,现将学习到的知识小结一下。
测试环境:
系统:64位win10系统
jdk版本:1.8.0_191
一.构建稳定的JVM虚拟机实例
要查看JVM相关的运行参数,首先要构建一个稳定运行的JVM实例,想想你写的第一个java程序helloworld。对,就用helloworld构建一个稳定的JVM虚拟机实例。
1.编辑java源文件,创建HelloWorld.java文件,使用文本编辑工具(本篇使用的是Note pad++)编辑
public class HelloWorld {
public static void main(String[] args) {
System.out.print("args[0] = " + args[0]);
}
}
这里有一个稍稍不同的是需要给main方法传递一个参数,以前写的helloworld主方法是不需要传递参数的。
2.编译java源文件
打开一个cmd窗口,切换到java文件所在的目录,本篇使用的J盘根目录,执行以下命令。
javac HelloWorld.java
可以看到目录下生成字节码文件HelloWorld.class。
3.运行helloworld程序,执行以下命令。
java HelloWorld
可以看到程序运行成功。
4.上面的程序执行时候会启动一个JVM,现在使用命令来查看下JVM。
jps
jps是用来查看系统中的java进程(JVM)的命令,这里没有显示出刚才运行的HelloWorld进程,这是因为因为程序执行完输出语句后就结束了,程序结束JVM就关闭了,那如何让JVM持续存在呢?自然想到让程序一直跑,不要结束,最简单的就是写一个死循环,这样程序一直跑,JVM也会稳定存在。
5.改写HelloWorld程序,让其一直运行。
public class HelloWorld {
public static void main(String[] args) {
while(true){
System.out.println("args[0] = " + args[0]);
}
}
}
改成以上的代码,可以保持程序一直执行,JVM就可以稳定存在。
6.修改代码后,重复执行以上的编译执行流程,可以看到程序一直输出。
7.现在程序一直执行,但当前cmd却不能再执行其他命令,如何查看?再新开一个cmd窗口,执行以下命令。
jps
可以看到运行的HelloWorld进程,即一个稳定的JVM虚拟机实例。
二.查看JVM默认参数配置
上面我们得到了一个持续的java进程,即一个稳定的JVM虚拟机。下面来看下jvm的相关参数。
1.在命令行中执行以下命令,查看JVM堆的信息。
jmap -heap pid
其中pid为HelloWorld的进程号,这里为90948。
从上图可以看到JVM堆的信息,有几个参数需要解释一下。
先做一下说明,java堆一般是由下面三块构成。
java堆 = 年轻代+年老代+持久代
MaxHeapSize:堆的最大大小
NewSize:年轻代(Young)的初始大小
MaxNewSize:年轻代的最大大小
OldSize:老年代的大小
NewRatio:新生代(Eden + 2*S)与老年代(不包括永久区)的比值
SurvivorRatio:2个Survivor区和Eden区的比值
(关于NewRatio和SurvivorRatio参考:https://blog.csdn.net/zlts000/article/details/79430298)
那为什么没有看到持久代的参数呢?我开始也想不明白
原来与jdk的版本有关,jdk1.8中取消了持久代,改为元空间,上面的参数metaSpaceSize即元数空间的大小。
下面是各个区的具体参数截图:
年轻代 = Eden+From+To
年老代 = Old
上面有两个参数,需要再次说明下
NewRatio:新生代(Eden + 2*S)与老年代(不包括永久区)的比值
SurvivorRatio:2个Survivor区和Eden区的比值
NewRatio默认值是2,意思是年轻代与年老代占比为1:2,即年轻代占对空间1/3,年老代占2/3。
SurvivorRatio默认是8,整个即在年轻代空间中,Eden区占8/(1+1+8)=4/5,两个survivor各占1/10。
三.手工配置JVM启动参数
弄清楚了上面的各个参数的含义以后,就可以对JVM的参数进行配置。
1.先看下JVM常用的配置项。
-Xms3550m:设置JVM初始堆内存为3550m
-Xmx3550m:设置JVM最大可用堆内存为3550M
-Xmn1024m:设置年轻代大小为1024m。
-Xss128k:设置每个线程的栈大小。
2.设置JVM启动参数,设置堆空间大小。
如何在启动JVM的时候设置参数呢,只需要在运行java程序的java命令后更上相应参数即可。
执行以下命令:
java -Xms512M -Xmx512M HelloWorld hello
然后再另一个cmd中输入jps和jmap命令:
jps
jmap -heap pid
可以看到:
可以看到MaxHeapSise变为512M,即为设置的堆512M。
NewSize和OldSize相比默认值发生改变,但年轻代与年老代的比率还是1:2。
3.再次设置,加入手工设置年轻代和栈大小。
java -Xms512M -Xmx512M -Xmn256M -Xss256K HelloWorld hello
再次查看内存分配:
可以看到,手工设置年轻代的大小生效,年轻代与年老代的比率不再为1:2。年老代 = 堆大小 - 年轻代。
参考:http://ifeve.com/useful-jvm-flags-part-4-heap-tuning/
https://blog.csdn.net/zlts000/article/details/79430298
https://blog.csdn.net/qq_36666651/article/details/80286738
https://www.cnblogs.com/w-wfy/p/6415856.html
https://www.cnblogs.com/gaigaichen/p/6843283.html