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下面找到并打开

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得内存信息得获取及分析得一些简单介绍。

原文地址:https://www.cnblogs.com/wuzhenzhao/p/12469403.html