Overview

  • 定位Java进程
  • Java 进程状态
  • Java 启动参数
  • Jvm 调优实战
  • Other Command

以下命令和测试均在Java8环境执行,有些命令可能因版本情况不适用.

定位java进程

  1. 利用java命令查看进程情况

jps -l -> /proc/pid

  1. 利用系统命令搜索进程

ps -ef |grep "process_name"

Java 进程状态

java进程状态有哪些?

  1. 查看的pid (即如何定位java进程)
  2. 当前进程启动的参数信息
  3. 所占用的内存 cpu 磁盘空间等
  4. jvm状态(gc信息 堆信息 栈信息等)

当前进程启动的参数信息

本机的初始化参数: java -XX:+PrintFlagsInitial

进程启动参数: jps -v 可以查看java进程启动时所带的参数信息

进程占用端口: netstat -anpo |grep pid

进程情况: ps -ef |grep pid

所占用的内存 cpu 磁盘空间等

内存占用情况 pmap -d pid 循环打印内存占用 while true; do pmap -d 3447 | tail -1; sleep 2; done

文件夹大小 du -sh dir_name

当前磁盘大小 df -h .

ls -l 命令显示的是这个目录节点信息占的大小,du 命令计算的这个目录下所有文件数据的总和。

线程状态

linux 进程的线程数: pstree -p pid ps -Lf pid

jvm 当前线程数: jstack pid | grep 'java.lang.Thread.State' | wc -l

当前线程都处于什么状态: jstack pid | 'java.lang.Thread.State' | grep 'java.lang.Thread.State' | sort | uniq -c |sort -n

线程状态含义 及监测

     9    java.lang.Thread.State: RUNNABLE
      2    java.lang.Thread.State: TIMED_WAITING (parking)
      1    java.lang.Thread.State: TIMED_WAITING (sleeping)
      2    java.lang.Thread.State: WAITING (on object monitor)
     18    java.lang.Thread.State: WAITING (parking)

java 线程状态文章 => jstack java线程

JVM状态

jvm内存占用状态: jmap -heap

线上gc查看: jstat -gc pid

栈日志导出: jstack pid > jstack.log

堆日志导出: jmap -dump:format=b,file=heap.log pid

查找内存占用: jmap -histo pid| head -20

GC原因查询: jstat -gccause pid

类加载器时间: jstat -class pid

查看垃圾收集器默认=> java -XX:+PrintCommandLineFlags -version

查看垃圾收集器当前进程 => jmap -heap pid |grep GC

Concurrent Mark-Sweep GC :CMS回收器
 Mark Sweep Compact GC:串行GC(Serial GC)
 Parallel GC with 2 thread(s): 并行GC(ParNew)

调整垃圾收集器

Java 启动参数

  1. jvm版本对应的启动参数
  2. 启动参数分类(额外日志型,项目优化)

Official Guide

官方文档 描述
Java HotSpot VM Options HotSpotVM 参数
Java SE 8 Documentation Java8 参数文档
Java11 Virtual Machine Guide Java11 虚拟机指引

项目常见参数配置

其配置的就是 堆、栈、元空间、新生代老年代、垃圾收集器。

的大小 一般设置成一样的,防止内存在增加或者减少时的内存抖动
-Xms1024m (堆最大大小)
-Xmx1024m (堆默认大小)

的最大深度大小 其值越大 创建线程数越少,其值越小 栈的深度越小
-Xss256k (棧最大深度大小)

元空间大小 spring boot在启动时会load大量的类和卸载大量的类

-XX:MetaspaceSize=128m (元空间默认大小)
-XX:MaxMetaspaceSize=128m (元空间最大大小)

④Other 其他

-Xmn256m (新生代大小)

-XX:SurvivorRatio=8 (新生代分区比例 8:2)
-XX:+UseConcMarkSweepGC (指定使用的垃圾收集器,这里使用CMS收集器)
-XX:+PrintGCDetails (打印详细的GC日志)

知识点:

JDK8之后把-XX:PermSize 和 -XX:MaxPermGen移除了,取而代之的是
-XX:MetaspaceSize=128m (元空间默认大小)
-XX:MaxMetaspaceSize=128m (元空间最大大小)

元空间 => JDK 8开始把类的元数据放到本地化的堆内存(native heap)中,这一块区域就叫Metaspace.

使用本地化的内存有什么好处呢?最直接的表现就是java.lang.OutOfMemoryError: PermGen 空间问题将不复存在。不过,让Metaspace变得无限大显然是不现实的,因此我们也要限制Metaspace的大小:

使用-XX:MaxMetaspaceSize参数来指定Metaspace区域的大小。JVM默认在运行时根据需要动态地设置MaxMetaspaceSize的大小。

Spring Boot 项目启动就进行FullGc的问题

以前只认为,Metaspace区是保存在本地内存中,是没有上限的,经查阅资料才发现,原来JDK8中,XX:MaxMetaspaceSize确实是没有上限的,最大容量与机器的内存有关;但是XX:MetaspaceSize是有一个默认值的:21M。问题就出在这里。

JVM关于元空间配置

问题 => 在工作过程中,遇到一个问题:Tomcat在重启或者发布的时候,会有多次的full GC。

额外日志

GC日志信息

-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps

输出gc日志到文件 -Xloggc:/path/to/gc.log

完整命令 java -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:gc.log

打印类加载信息

类加载 卸载信息 -XX:+TraceClassLoading -XX:+TraceClassUnloading

GC日志在线分析

java命令行信息

要获取VM命令行,请运行

jcmd pid VM.command_line

要查看JVM标志的完整列表,请运行

jcmd pid VM.flags -all

JVM 调优实战

首先为什么要调优?

  1. 优化项目的性能,即减少GC
  2. 减少应用的内存占用
  3. 优化到什么程度

调优步骤:

  1. 获取项目的jvm配置及相关信息 jps -v

  2. 获取项目的gc信息 jstat -gccause

  3. 获取项目的垃圾收集器和现在一些信息 jmap -heap 判断是否出现了内存泄露 使用jmap -histo:live可以强制进行FGC:

存泄露的判断方法是,当请求不断增加,有一部分内存没有被释放.内存没有被释放.认为即对象没有被释放-> jmap -dump:live,file=path 这个命令会进行full gc,并且输出文件 Jprofile

  1. 对指标进行调优 FGC次数 理想状态FGC次数 频次越低越好(综合来看) 但是FGC次数的降低一般意味着内存的占用提升

  2. 调整JVM 启动参数 .... 并加以观测

常见手段

调整堆大小到合适大小,减少GC次数

适当通过 -Xmn”命令调节新生代大小,最大限度降低新对象直接进入老年代的情况

性能指标

MinorGC 执行时间不到50ms; Minor GC 执行不频繁,约10秒一次; Full GC 执行时间不到1s; Full GC 执行频率不算频繁,不低于10分钟1次。

内存泄露观测

jmap -dump:format=b,file=myfile.hprof pid

一般文件都比较大需要压缩 => 比如用 zip xxx.zip file

在7000端口启动服务,貌似查不出来啥: jhat file.hprof

以下是两个内存观测工具

Jprofile 日志文件查看

Memory Analyzer Tools

JVM 查看对象大小

jmap -histo pid | head -20

System.out.println(RamUsageEstimator.sizeOf(root))

     <!--jol-core-->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>4.0.0</version>
        </dependency>

代码层面优化

减少创建对象的数量; 减少使用全局变量和大对象;

Other Command

项目管理

  1. 生成软连接

ln -s from to (文件,文件夹都可链接)

影响线上程序

  1. 进行强制Gc

jmap -histo:live

常见java command

jinfo 命令

使用 jinfo 可以在不重启虚拟机的情况下,可以动态的修改 jvm 的参数。尤其在线上的环境特别有用

jinfo -flag +PrintGCDetails pid
jinfo -flag +PrintGC pid

实用的工具

IDEA debug线上代码

java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=9190 -jar debug-demo.jar

相关配置Link

tcpdump抓包

tcpdump -i eth0 -A -s0 port 9052

-i 指定网卡 -A 表示使用 ASCII 字符串打印报文的全部数据 -s0 捕获所有数据,默认只抓96字节

写在最后

以上命令要不断练习,在练习过程中不断体会jvm原理等.