jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效

jvm相关的指令简单解析

jps :JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
命令格式
jps [options] [hostid]
option参数
-l : 输出主类全名或jar路径
-q : 只输出LVMID
-m : 输出JVM启动时传递给main()的参数
-v : 输出JVM启动时显示指定的JVM参数
其中[option]、[hostid]参数也可以不写。

jstat
jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
Option  Displays…
class   class loader的行为统计。
compiler HotSpt JIT编译器行为统计。
gc  垃圾回收堆的行为统计。
gcnew   新生代行为统计。
......
实例
jstat -gcnew 4502
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
 512.0  512.0    0.0   64.0  1  15  512.0  23552.0  19612.0  62079 2264.691

jstat -gc 4502
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
209664.0 209664.0  0.0   12744.5 629248.0 510460.3 3145728.0   150092.5  204144.0 200261.6 22176.0 21505.2   1321   32.334  442    74.518  106.852

jmap
jmap -heap [pid] 要注意的是在使用CMS GC 情况下,jmap -heap的执行有可能会导致JAVA 进程挂起
jmap -histo [pid] 查看JVM堆中对象详细占用情况
jmap -dump:format=b,file=文件名 [pid] 导出整个JVM 中内存信息
jmap -histo:live pid命令  //这个会立即触发fullgc

jstack
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。
-F : 当正常输出请求不被响应时,强制输出线程堆栈
-l : 除堆栈外,显示关于锁的附加信息
-m : 如果调用到本地方法的话,可以显示C/C++的堆栈
jstack [option] pid >head.log

jvm中堆使用情况一般查询过程

  1. 查看java程序对应的pid :jps指令查看  后面带有Bootstrap的就是。  
  2. 查看整个JVM内存状态:jmap -heap [pid] 要注意的是在使用CMS GC 情况下,jmap -heap的执行有可能会导致JAVA 进程挂起
  3. 查看JVM堆中对象详细占用情况 jmap -histo [pid]
  4. 导出整个JVM 中内存信息 jmap -dump:format=b,file=文件名 [pid]
  5. 使用eclipse的MAT分析内存文件

如:
Jps 找到java对应的进程号
jmap -dump:format=b,file=文件名 [pid]
jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效

jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效
文件生成后 用eclipse的 MAT插件就可以查看,如果没有安装可以借鉴
https://blog.****.net/u010335298/article/details/52233689
然后重启eclipse,选择File open打开文件即可开始分析

dump OOM内容的两种方式

1.输出方式有两种方式:  
方式一:命令参数jmap -dump:format=b,file=xxx.hprof  pid   
方式二:jvm配置增加oom时自动dump,配置如下
 -XX:+HeapDumpOnOutOfMemoryError 
 -XX:HeapDumpPath=/export/Domains/dump.hprof  
推荐方式二,更加灵活方便   

内存溢出分析实例

背景:
运维监控,统计深圳机场限额使用情况,手动写SQL结果集过大,导致java.lang.OutOfMemoryError异常,系统报警。
问题排查步骤:
1.  收到报警短信,第一时间查看云信对应的系统报什么错误信息,找出可疑问题。
2.  找运维导出内存溢出的快照文件
3.  使用MAT内存分析工具,分析报错报告,找出问题所在

使用MAT分析报错报告流程

1.  先查看leak Suspects,找出最有可能出现问题的对象
jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效
2.在向下看,可以确定两个可以对象,java.lang.Thread 
和com.mysql.jdbc.JDBC4ResultSet ,可以定位是线程和 sql问题
jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效
针对不同的可能影响内存溢出的问题,点击Details可看到具体的信息
Shallow Heap指的是所有的实例的内存总和。Retained Heap指的是所有类实例被分配的内存总和,retained heap占用最多的是object数组
jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效
com.mysql.jdbc.ByteArrayRow被实例化了3,055,923次
jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效
在Accumulated Objects列表中,我们可以看见创建的大量的对象。
jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效
3.查看See stacktrace,查看堆栈
jvm指令,jvm内存溢出原因分析过程和实例,MAT分析使用,NewRatio无效
有上图的的三处基本可以定位到,gcpm项目内com.suning.gcpm.admin.business.commonQuery.CommonQueryBussiness.commonSQL ,这个方法的问题,再查看代码,
确定是后台执行sql的问题。
这样就定位了问题,找到了罪魁祸首
因为刚刚,我在用后台查在生产查询了一个sql,并且没有返回结果。
Sql要查询的结果是 top_org_code= '6054372338'用户下,账期支付方式
并且改变的限额>=已有的限额

user_code用户表
zs_credit_limit_useinfo限额记录表
zs_credit_limit_info   限额表 
SELECT c.credit_value, c.used_credit_value ,u.change_value FROM zs_credit_limit_useinfo u 
LEFT JOIN zs_user z ON  z.user_code=u.cust_no
LEFT JOIN zs_credit_limit_info c ON  c.cust_no=c.cust_no
WHERE u.change_reason='08' 
AND z.top_org_code= '6054372338'
AND u.change_value>=c.credit_value

Sql问题:关联条件写错,c.cust_no=c.cust_no

结论:生产环境查询sql注意事项:
1.  本地执行,保证语法正确
2.  生产sql先查看一下执行计划,有没有性能瓶颈
3.  先查询count(),先查总数,再执行查询结果集
4.大促敏感时期,生产操作都要注意
5.如果关联表的结果集过大,可以找DBA导出生产的SQL,导入本地库,关联查询
6.手动分页查询

 

NewRatio无效实例

jmap -heap 10284,结果如下:
Attaching to process ID 10284, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b14

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 6442450944 (6144.0MB)
   NewSize                  = 134217728 (128.0MB)
   MaxNewSize               = 134217728 (128.0MB)
   OldSize                  = 2013265920 (1920.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 104857600 (100.0MB)
   used     = 55912680 (53.322486877441406MB)
   free     = 48944920 (46.677513122558594MB)
   53.322486877441406% used
From Space:
   capacity = 14680064 (14.0MB)
   used     = 613560 (0.5851364135742188MB)
   free     = 14066504 (13.414863586425781MB)
   4.179545811244419% used
To Space:
   capacity = 14155776 (13.5MB)
   used     = 0 (0.0MB)
   free     = 14155776 (13.5MB)
   0.0% used
PS Old Generation
   capacity = 2013265920 (1920.0MB)
   used     = 566038448 (539.8163299560547MB)
   free     = 1447227472 (1380.1836700439453MB)
   28.11543385187785% used

45234 interned Strings occupying 4779152 bytes.

问题:
old计算出来是280M,实际1920M   ???????????????
NewRatio 与实际新生代和老生代占用内存不一致原因???


获取当前linux上jvm配置
ps -ef | grep java

work     10284     1  1 Feb12 ?        02:09:26 /data/j2sdk/bin/java -Djava.util.logging.config.file=/data/zhipin-bi/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Xms2048M -Xmx6144M -Xmn128M -XX:PermSize=128M -XX:MaxPermSize=256m -XX:-OmitStackTraceInFastThrow -Xdebug -XX:+PrintTenuringDistribution -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Djava.security.egd=file:/dev/./urandom -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -Xloggc:/data/zhipin-bi/tomcat/bin/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/zhipin-bi/tomcat/bin/dump.hprof

 -Xms2048M -Xmx6144M -Xmn128M,这三个配置已经有了,实际上NewRatio就会无效,但是jmap -heap 的结果中NewRatio是怎么来的呢?