JVM常用参数/命令/工具
JVM参数类型:
标准参数:
-version,-help,-server,-cp
-X参数:
非标准参数,也就是在JDK各个版本中可能会变动
-Xint 解释执行,-Xcomp 第一次使用就编译成本地代码,-Xmixed 混合模式,JVM自己来决定
-XX参数:
使用得最多的参数类型,非标准化参数,相对不稳定,主要用于JVM调优和Debug。
- Boolean类型,格式:-XX:[+-]<name> ,+或-表示启用或者禁用name属性,比如:-XX:+UseConcMarkSweepGC 表示启用CMS类型的垃圾回收器 -XX:+UseG1GC 表示启用G1类型的垃圾回收器
- 非Boolean类型,格式:-XX<name>=<value>表示name属性的值是value,比如:-XX:MaxGCPauseMillis=500
其他参数:
- -Xms1000等价于-XX:InitialHeapSize=1000
- -Xmx1000等价于-XX:MaxHeapSize=1000
- -Xss100等价于-XX:ThreadStackSize=100
所以这块也相当于是-XX类型的参数
查看参数:
java -XX:+PrintFlagsFinal -version
值得注意的是"="表示默认值,":="表示被用户或JVM修改后的值。要想查看某个进程具体参数的值,可以使用 jinfo,一般要设置参数,可以先查看一下当前参数是什么,然后进行修改。
设置参数的方式:
- 开发工具中设置比如IDEA,eclipse设置 VM options。
- 运行jar包的时候:java -XX:+UseG1GC xxx.jar。
- web容器比如tomcat,可以在脚本中的进行设置,catalina.sh。
- 通过jinfo实时调整某个java进程的参数(参数只有被标记为manageable的flags可以被实时修改)。
我们可以通过IDEA进行设置参数并且打印参数信息来体会一下这个过程,首先设置堆内存大小和参数打印 -Xmx100M -Xms100M -XX:+PrintFlagsFinal
启动项目就可以看到跟上面在 CMD 窗口执行 java -XX:+PrintFlagsFinal 获取到的信息:
查询+PrintFlagsFinal的值:
查询堆内存大小MaxHeapSize , 注意这里的 104857600 (Byte) /1024 /1024 =100MB:
常用参数含义:
- -XX:CICompilerCount=3 最大并行编译数,如果设置大于1,虽然编译速度会提高,但是同样影响系统稳定性,会增加JVM崩溃的可能
- -XX:InitialHeapSize=100M 初始化堆大小 简写-Xms100M
- -XX:MaxHeapSize=100M 最大堆大小 简写-Xm x 100M
- -XX:NewSize=20M 设置年轻代的大小
- -XX:MaxNewSize=50M 年轻代最大大小
- -XX:OldSize=50M 设置老年代大小
- -XX:MetaspaceSize=50M 设置方法区大小
- -XX:MaxMetaspaceSize=50M 方法区最大大小
- -XX:+UseParallelGC 使用UseParallelGC 新生代,吞吐量优先
- -XX:+UseParallelOldGC 使用UseParallelOldGC 老年代,吞吐量优先
- -XX:+UseConcMarkSweepGC 使用CMS 老年代,停顿时间优先
- -XX:+UseG1GC 使用G1GC 新生代,老年代,停顿时间优先
- -XX:NewRatio 新老生代的比值,比如-XX:Ratio=4,则表示新生代:老年代=1:4,也就是新生代占整个堆内存的1/5
- -XX:SurvivorRatio 两个S区和Eden区的比值,比如-XX:SurvivorRatio=8,也就是(S0+S1):Eden=2:8,也就是一个S占整个新生代的1/10
- -XX:+HeapDumpOnOutOfMemoryError 启动堆内存溢出打印当JVM堆内存发生溢出时,也就是OOM,自动生成dump文件
- -XX:HeapDumpPath=heap.hprof 指定堆内存溢出打印目录 表示在当前目录生成一个heap.hprof文件
- XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:$CATALINA_HOME/logs/gc.log :打印出GC日志 可以使用不同的垃圾收集器,对比查看GC情况
- -Xss128k 设置每个线程的堆栈大小 经验值是3000-5000最佳
- -XX:MaxTenuringThreshold=6 提升年老代的最大临界值 默认值为 15
- -XX:InitiatingHeapOccupancyPercent 启动并发GC周期时堆内存使用占比G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45.
- -XX:G1HeapWastePercent 允许的浪费堆空间的占比默认是10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC。
- -XX:MaxGCPauseMillis=200ms G1最大停顿时间暂停时间不能太小,太小的话就会导致出现G1跟不上垃圾产生的速度。最终退化成Full GC。所以对这个参数的调优是一个持续的过程,逐步调整到最佳状态。
- -XX:ConcGCThreads=n 并发垃圾收集器使用的线程数量 默认值随JVM运行的平台不同而不同
- -XX:G1MixedGCLiveThresholdPercent=65 混合垃圾回收周期中要包括的旧区域设置占用率阈值 默认占用率为 65%
- -XX:G1MixedGCCountTarget=8 设置标记周期完成后,对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数默认8次混合垃圾回收,混合回收的目标是要控制在此目标次数以内
- -XX:G1OldCSetRegionThresholdPercent=1 描述Mixed GC时,Old Region被加入到CSet中默认情况下,G1只把10%的Old Region加入到CSet中
常用命令:
jps :
查看java进程:
jinfo :
实时查看和调整JVM配置参数 jinfo -flag name PID 查看某个java进程的 name属性的值
jinfo -flag MaxHeapSize PID :如下图显示最大堆大小
jinfo -flag UseG1GC PID :如下图未使用G1GC
参数只有被标记为manageable的 flags 可以被实时修改,jinfo -flag [+|-] PID:
jinfo -flag [+|-]name pid 描述:开启或者关闭对应名称的参数
查看曾经赋过值的一些参数 jinfo -flags PID
jstat :
查看虚拟机性能统计信息,查看类装载信息,jstat -class PID 1000 10 查看某个java进程的类装载信息,每1000毫秒输出一次,共输出10次
查看垃圾收集信息 jstat -gc PID 1000 10
jstack:
查看线程堆栈信息 ,jstack PID
排查死锁案例 DeadLockDemo:
public class DeadLockDemo {
public static void main(String[] args) {
DeadLock d1 = new DeadLock(true);
DeadLock d2 = new DeadLock(false);
Thread t1 = new Thread(d1);
Thread t2 = new Thread(d2);
t1.start();
t2.start();
}
}
//定义锁对象
class MyLock {
public static Object obj1 = new Object();
public static Object obj2 = new Object();
}
//死锁代码
class DeadLock implements Runnable {
private boolean flag;
DeadLock(boolean flag) {
this.flag = flag;
}
public void run() {
if (flag) {
while (true) {
synchronized (MyLock.obj1) {
System.out.println(Thread.currentThread().getName() + "----if 获得obj1锁");
synchronized (MyLock.obj2) {
System.out.println(Thread.currentThread().getName() + "--- -if获得obj2锁");
}
}
}
} else {
while (true) {
synchronized (MyLock.obj2) {
System.out.println(Thread.currentThread().getName() + "----否则 获得obj2锁");
synchronized (MyLock.obj1) {
System.out.println(Thread.currentThread().getName() + "--- -否则获得obj1锁");
}
}
}
}
}
}
运行结果:
jps 查看进程并且打印栈信息:
将打印的信息拉到最下面会发现死锁的信息:
jmap:
生成堆转储快照,打印出堆内存相关信息,先设置虚拟机参数:-XX:+PrintFlagsFinal -Xms300M -Xmx300M,然后启动。
dump出堆内存相关信息:jmap -dump:format=b,file=heap.hprof PID 。要是在发生堆内存溢出的时候,能自动dump出该文件就好了一般在开发中,JVM参数可以加上下面两句,这样内存溢出时,会自动dump出该文件,设置 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof 即可在OOM的时候dump出该文件。关于dump下来的文件,一般dump下来的文件可以结合工具来分析。
常用工具:
参数也了解了,命令也知道了,关键是用起来不是很方便,要是有图形化的界面就好了。一定会有好事之者来做这件事情。
jconsole:
JConsole工具是JDK自带的可视化监控工具。查看java应用程序的运行概况、监控堆信息、永久区使用情况、类加载情况等。在${JAVA+HOME}/bin下面找到并打开
远程连接需要配置:
java -Djava.rmi.server.hostname=10.160.13.111 #远程服务器ip,即本机ip -Dcom.sun.management.jmxremote #允许JMX远程调用 -Dcom.sun.management.jmxremote.port=3214 #自定义jmx 端口号 -Dcom.sun.management.jmxremote.ssl=false # 是否需要ssl 安全连接方式 -Dcom.sun.management.jmxremote.authenticate=false #是否需要秘钥 -jar test.jar
jvisualvm:
在${JAVA+HOME}/bin下面找到并打开,监控本地Java进程:可以监控本地的java进程的CPU,类,线程等
监控远端Java进程:比如监控远端tomcat,部署在阿里云服务器上的tomcat
在visualvm中选中“远程”,右击“添加”
主机名上写服务器的ip地址,比如192.168.1.101,然后点击“确定”
右击该主机“192.168.1.101”,添加“JMX”[也就是通过JMX技术具体监控远端服务器哪个Java进程]
要想让服务器上的tomcat被连接,需要改一下 bin/catalina.sh 这个文件.注意下面的8998不要和服务器上其他端口冲突:
JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=192.168.1.101 -Dcom.sun.management.jmxremote.port=8998 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.ma
nagement.jmxremote.access.file=../conf/jmxremote.access -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password"
在 ../conf 文件中添加两个文件jmxremote.access和jmxremote.password,jmxremote.access 文件:
guest readonly
manager readwrite
jmxremote.password 文件:
guest guest
manager manager
授予权限 : chmod 600 *jmxremot*
Arthas :
github :https://github.com/alibaba/arthas 。Arthas 是Alibaba开源的Java诊断工具,采用命令行交互模式,是排查jvm相关问题的利器。Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。当你遇到以下类似问题而束手无策时,Arthas 可以帮助你解决:
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
Arthas 支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。
curl -O https://alibaba.github.io/arthas/arthas-boot.jar java -jar arthas-boot.jar # 然后可以选择一个Java进程
启动后选择对应的Java进程:
Print usage :java -jar arthas-boot.jar -h .
常用命令:具体每个命令怎么使用,大家可以自己查阅资料
version:查看arthas版本号 help:查看命名帮助信息 cls:清空屏幕 session:查看当前会话信息 quit:退出arthas客户端 --- dashboard:当前进程的实时数据面板 thread:当前JVM的线程堆栈信息 jvm:查看当前JVM的信息 sysprop:查看JVM的系统属性 --- sc:查看JVM已经加载的类信息 dump:dump已经加载类的byte code到特定目录 jad:反编译指定已加载类的源码 --- monitor:方法执行监控 watch:方法执行数据观测 trace:方法内部调用路径,并输出方法路径上的每个节点上耗时 stack:输出当前方法被调用的调用路径 ......
MAT:
Dump信息包含的内容
- All Objects:Class, fields, primitive values and references
- All Classes:Classloader, name, super class, static fields
- Garbage Collection Roots:Objects defined to be reachable by the JVM
- Thread Stacks and Local Variables:The call-stacks of threads at the moment of the snapshot, and per-frame information about local objects
获取Dump文件
@RestController public class HeapController { List<Person> list=new ArrayList<Person>(); @GetMapping("/heap") public String heap() throws Exception{ while(true){ list.add(new Person()); Thread.sleep(1); } } }
启动springboot,访问上面这个接口造成内存溢出。
- 手动:jmap -dump:format=b,file=heap.hprof PID
- 自动:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof
使用:
Histogram:Histogram可以列出内存中的对象,对象的个数及其大小,Class Name:类名称,java类名,Objects:类的对象的数量,这个对象被创建了多少个,Shallow Heap:一个对象内存的消耗大小,不包含对其他对象的引用,Retained Heap:是shallow Heap的总和,即该对象被GC之后所能回收到内存的总和
右击类名--->List Objects--->with incoming references--->列出该类的实例。右击Java对象名--->Merge Shortest Paths to GC Roots--->exclude all ...--->找到GCRoot以及原因。如下图我们会发现EntityDemo这个类得实例有10W多个。
Leak Suspects:查找并分析内存泄漏的可能原因Reports--->Leak Suspects--->Details
他就会告诉我们哪里存在问题,然后我们就可以粗略定位到问题,然后去看代码就能定位到。以上就是关于JVM得内存信息得获取及分析得一些简单介绍。