BESAppServer中JavaDump分析

来源:互联网 发布:淘宝查gsx会泄露信息吗 编辑:程序博客网 时间:2024/05/16 18:17

 

1.1. Java dump概述

JavaDump即Java虚拟机的运行时快照。制作和分析dump时,常常将当时Java虚拟机运行时的状态和信息保存到dump文件。

dump分类:

线程Dump,包含JVM进程中所有线程的运行状态。纯文本格式。

堆Dump,包含线程Dump以及所有堆对象的状态。二进制格式。

 

1.2. 制作和分析Dump

1.2.1. 常见Java虚拟机

不同Java虚拟机的Dump规范不完全相同。线程dunp为纯文本格式,各虚拟机略有不同。

Java虚拟机类型

说明

HotSpot VM

原Sun的Java虚拟机实现。堆dump为HPROF二进制格式。

IBM J9 VM

IBM的Java虚拟机,常见于IBM的AIX等机器。堆dump为PHD二进制格式。

OpenJDK

开源版本的Java虚拟机实现,与HotSpot VM实现大部分相同。堆dump为HPROF二进制格式。

JRockit

原BEA的Java虚拟机实现。堆dump为HPROF二进制格式。

HP JDK

HP服务器上的Java虚拟机实现。堆dump为HPROF二进制格式。

 

       IBMPortable Heap Dump (PHD): 这个专有的 IBM 格式只包含进程中每个 Java 对象的类型和大小,以及这些对象之间的关系。这个转储文件格式远远小于其他格式,并且只包含最少的信息。但是,这些数据通常对于分析内存泄漏和了解应用程序基本架构和范围而言是足够的。

       HPROF二进制转储文件: HPROF二进制转储文件在 IBMPHD 格式中包含了所有数据表现方式,以及 Java 对象和线程内部的基本数据类型,您可以查看对象中域的值,查看在转储文件产生时有哪些方法在被执行。其他基本数据使 HPROF 转储文件明显比 PHD 格式的转储文件要大;它们大约与所使用的 Java 堆一样大。

 

1.2.2. 制作Java Dump

在不同的操作系统平台、不同的Java虚拟机环境下,使用图形化或命令行工具,生成指定Java进程的Dump并保存到文件。

使用JDK自带工具,连接BES实例,制作dump

HotSpot 运行时环境:

基于 HotSpot 的 Java 运行时只能够生成 HPROF 格式的转储文件。

可以先通过ps/jps:查看本机的Java中进程信息。然后使用jstack打印线程的栈信息,制作线程Dump。

知识点:

Solaris 下/usr/bin/ps会截短进程名称,很多时候没法知道完整的进程名称,很不方便。而/usr/ucb/ps有参数可以显示全名:

/usr/ucb/ps -auxww |grep java

 

制作heap dump有以下几种方法:

方法

使用说明

Jmap工具

jmap位于 JDK 的 bin 目录,它提供了一种从运行中的进程请求一个 HPROF 转储文件的选项。在 Java 5 中,要使用:

jmap -dump:format=b pid

而在 Java 6 中,要使用以下命令,其中 live 是可选的,表示只返回正在写到转储文件进程 ID (PID) 的 “live” 对象:

jmap -dump[live,]format=b,file=filename pid

Jconsole工具

dumpHeap 操作是基于 JConsole 的 HotSpotDiagnostic MBean 提供的。这个操作要求必须生成一个 HPROF Dump。

JVM事件

遇到 OutOfMemoryError 时: 如果运行中应用程序设置了 -XX:+HeapDumpOnOutOfMemoryError 命令行选项,那么当出现OutOfMemoryError 错误时就会有一个 HPROF 格式的转储文件生成。在生产系统中使用这种方法非常好,因为它几乎一直需要分析内存问题,并且它不会引起额外的性能开销。在旧版本的基于 HotSpot 的 Java 运行时中,每次 JVM 执行时这个事件所产生的堆转储文件数量并没有限制;而在新的版本中,每次 JVM 执行的事件所生成的堆转储文件具有一个最大值。

 

IBM JDK运行时环境:

可以通过 -Xdump:what 选项查看默认dump触发事件即配置。

事件

描述

可用过滤

示例

gpf

一般保护故障(崩溃)

-Xdump:system:events=gpf

user

用户触发信息(SIGQUIT 或 Ctrl+Break)

-Xdump:system:events=user

vmstop

VM 关闭,包括调用System.exit()

退出代码

-Xdump:system:events=vmstop,filter=#0..#10
在 VM 关闭时生成带有 0 至 10 退出代码的系统转储文件。

load

类加载

类名称

-Xdump:system:events=load,filter=com/ibm/example/Example
当 com.ibm.example.Example 类加载时生成一个系统转储文件。

unload

类卸载

类名称

-Xdump:system:events=unload,filter=com/ibm/example/Example

当 com.ibm.example.Example 类卸载时生成一个系统转储文件。

throw

抛出一个异常

异常类名

-Xdump:system:events=throw,filter=java/net/ConnectException

当 ConnectException 产生时生成一个系统转储文件。

catch

捕捉到一个异常

异常类名

-Xdump:system:events=catch,filter=java/net/ConnectException
当 ConnectException 被捕捉时生成一个系统转储文件。

systhrow

JVM 将抛出一个 Java 异常。(这与 throw 事件不同,因为它只能由 JVM 内部检测到的错误条件触发。)

异常类名

-Xdump:system:events=systhrow,filter=java/lang/OutOfMemoryError
当 OutOfMemoryError 产生时生成一个系统转储文件。

allocation

分配一个 Java 对象

所分配对象的大小

-Xdump:system:events=allocate,filter=#5m
当分配大于 5MB 的对象时生成一个系统转储文件。

 

Jrokit运行环境:

先使用命令:

jrcmd <pid> help

得到相关的options。

线程dump:

jrcmd <pid> print_threads

堆dump:

jrcmd <pid> hprofdump filename=/home/bes/test.hprof

 

使用BES功能,制作dump

线程dump可使用CLI的threaddump命令制作或者通过BES Console制作;

CLI:

BESConsole:

堆dump,需要使用在bes中添加jvm参数,根据jvm参数使用说明制作;

 

1.2.3. 分析线程dump

分析线程Dump的工具

1.        Thread Dump Analyzer (TDA)

2.        IBM Thread and Monitor Dump Analyzer(TMDA)

 

原则

1.        结合代码阅读的推理。需要线程Dump和源码的相互推导和印证。

2.        造成问题的原因往往不会在调用栈上直接体现,一定格外注意线程当前调用乊前的所有调用。

3.        制作多份线程Dump,使用TMDA的比较功能,分析系统的连续状态。

 

线程状态

NEW,未启动的。不会出现在Dump中。

RUNNABLE,在虚拟机内执行的。

BLOCKED,受阻塞并等待监视器锁。

WATING,无限期等待另一个线程执行特定操作。

TIMED_WATING,有时限的等待另一个线程的特定操作。

TERMINATED,已退出的。

 

调用修饰

locked <地址> 目标:使用synchronized申请对象锁成功,监视器的拥有者。

waiting to lock <地址> 目标:使用synchronized申请对象锁未成功,在进入区等待。

waiting on <地址> 目标:使用synchronized申请对象锁成功后,释放锁幵在等待区等待。

parking to wait for <地址> 目标:park是基本的线程阻塞原语,不通过监视器在对象上阻塞。

线程动作

Runnable:状态一般为RUNNABLE。

in Object.wait():等待区等待,状态为WAITING或TIMED_WAITING。

waiting for monitor entry:进入区等待,状态为BLOCKED。

waiting on condition:等待区等待、被park。

sleeping:休眠的线程,调用了Thread.sleep()。

 

示例

示例1:

现象:某线程状态BLOCKED,线程动作wait on monitor entry,调用修饰waiting to lock总是一起出现。

推论:表示在代码级别已经存在冲突的调用。必然有问题的代码,需要尽可能减少其发生。

示例2:

现象:一个线程锁住某对象,大量其他线程在该对象上等待。

推论:存在同步块阻塞

 

一些技巧

1.        大胆猜测,小心证明。

2.        仔细地阅读代码。

3.        注意调用栈与众不同的线程。

 

1.2.4. 分析堆dump

分析堆dump的工具

1.        Java VisualVM:JDK自带。物理内存空闲多,简单查看系统信息、虚拟机参数、类、对象状态。支持OQL查询语言,及插件扩展。

2.        Memory Analyzer(MAT):Eclipse基金会开发。分析堆dump时建议使用。

3.        IBM HeapAnalyzer

 

堆Dump的内容

4.        系统信息、虚拟机属性。

5.        完整的线程Dump。

6.        所有类和对象的状态。

 

堆Dump分析的使用场景

1.        在出现内存不足、GC异常时,怀疑代码存在内存泄漏。制作堆Dump,找出生命周期错误关联的对象以及相关代码。可以通过jstat –gc pidinterval(s/ms)监控BES实例gc情况,示例:

 

2.        某些复杂场景下,需要查看对象的状态。

内存不足的错误

OutOfMemoryError年老代内存不足。

OutOfMemoryError:PermGen Space 永久代内存不足。

OutOfMemoryError:GC overhead limit exceed 垃圾回收时间占用系统运行时间的98%或以上。

 

使用技巧

1. 如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。

2. 要制作堆Dump可以直接使用jvm自带的jmap命令

3. 可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占用情况。

4. 使用jmap -histo:[live]查看堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。

5. 也可以使用 jmap-dump:format=b,file=<fileName>命令将堆信息保存到一个文件中,再借助jhat命令查看详细内容

6. 在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,把内存文件进行编号归档,便于后续内存整理分析。

1 0