jvm实战之-常用jvm命令的使用

各命令的使用

JMAP

1、查看内存信息,对象实例数、对象占有大小

jmap -histo 进程号>./log.txt

2、查看堆的配置信息和使用情况

jmap - heap 进程号

jvm实战之-常用jvm命令的使用_第1张图片
3、将堆的快照信息dump下来,使用java自带的jvisualvm.exe打开分析

jmap -dump:format=b,file=dump.hprof 进程号
Jstack

查看线程信息,死锁时用到可以查看线程阻塞信息

jstack -l 进程号 > jstack.log
jstat

查看gc日志

jstat -gc  进程号

jvm实战之-常用jvm命令的使用_第2张图片

持续打印gc日志

jstat -gc 进程号 1000 10
其他

1、jvisualvm.exe可以开启远程连接,但生产一般不用。只能在测试服务器上进行压测的时候可以开启。开启需要在服务器上加命令:自行百度
2、记录下outofmemory时的dump文件

-Xmx10M -Xms10M
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:/dump.dump

dump下来的文件使用java自带的jvisualvm.exe打开分析

实战例子

cpu飙高定位问题
  • top 查看占用较大的进程号
  • 使用 top -p 进程,再按大写的H 查看该进程下对应的线程情况
  • 找到占有最大的线程id
  • jstack -l 进程号
  • 用jstack打出来的线程nid和top -p 查到的线程进行对比。就能得到对应的代码信息
  • 注意jstack 里面的线程信息 nid是16进制的,top里面找到的线程信息需要转换一下
    jvm实战之-常用jvm命令的使用_第3张图片
优化full gc

目的:让朝生夕死的对象在年轻代就干掉,不要给他到达老年代
案例
线上系统频繁发生full gc。有卡顿,但是线上的系统压力也不是很大。
1、通过jstat -gc 进程号 查看gc情况
机器和GC情况

  • 机器配置:2核4G
  • JVM内存大小:2G
  • 系统运行时间:7天
  • 期间发生的Full GC次数和耗时:500多次,200多秒
  • 期间发生的Young GC 次数和耗时:1万多次,500多秒
  • 大致算下来每天会发生70多次Full GC,平均每小时3次,每次Full GC在400毫秒左右;每天会发生1000多次Young GC, 每分钟会发生一次,每次Young GC 在50毫秒左右
  • 上述数据对任何一个线上系统,用jstat -gc 进程号,可以轻松看出来,因为jstat显示出来的Full GC和Young GC的次数都是系统启动以来的总次数。可回看上方jstat -gc命令的介绍

JVM的参数设置如下

 -Xms1536M -Xmx1536M -Xmn512M -Xss256K -XX :SurvivorRatio=6 -XX:MetaspaceSize=256M
-XX:+UseParNewGC -xx:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly

计算各区大小

  • jvm总内存1536M

  • 新生代堆内存-Xmn512M,SurvivorRatio=6根据比例得知:伊甸园区:幸存1区:幸存2区 = 6:1:1。伊甸园区 384M,幸存1区 64M,幸存2区 64M(幸存1区与二区内存相同,是否是,进行youngGC的时候,将一区挪到二区,或从二区挪到一区)

  • 老年区 = 堆大小1536-新生代堆521 = 1G

  • 条件:youngGC 7天1万次,大概每隔1分钟发生一次youngGC,一分钟占满伊甸园区384M,每秒会产生6M对象

  • fullGC 大概每20分钟一次,因为XX:CMSInitiatingOccupancyFraction设置的75%。所有每20分钟大概有700M的对象移入老年代
    jvm实战之-常用jvm命令的使用_第4张图片
    验证调整
    分析为什么会频繁触发fullGC

  • youngGC 7天1万次

  • 平均一分钟一次youngGC

  • 也就是每60秒会占满伊甸园区384M

  • youngGC 在10秒到60秒一次算是比较正常的。而且每次youngGC完只剩下几十MB进入到幸存区,只是偶尔会有一两次幸存区放不下才会进到老年代。

  • 这里youngGC并不频繁,但是FULLGC却那么频繁有点反常

  • 猜测触发FULLGC很可能是有大对象或者触发空间担保机制进入到了老年代

  • 大对象是因为产生的对象伊甸园区放不下了,直接就放到了老年代

  • 这个时候我们通过jstat运行的时候就观察到一个现象,就是老年代里的内存占用在系统运行的时候,不知道为什么系统运行着运行着就会突然有几百MB的对象占据在里面,大概有五六百MB的对象,一直占据在老年代中。那只能是有大对象生成

  • 分析到这里就很简单了,就先用jstat命令观察老年代突然进入几百兆对象。然后将内存dump下来。Visual VM之类的可视化工具来分析dump内存快照

  • 直接定位出来那个几百MB的大对象,就是几个Map之类的数据结构。根据业务排查,有SQL会在特定场景下select * from tbl,后面的where条件都没有用上,导致查询出大量数据,从而这些对象都进入到老年代,引发fullGC

参考:https://www.jianshu.com/p/b6d2aa15c2a8

你可能感兴趣的:(jvm)