Q:检查内存泄露的工具有?
A: jmap生成dump转储文件,jhat可视化查看。
Q:某进程CPU使用率一直占满,用什么工具可以排查?
A:
top -Hp pid找到最占CPU的线程
然后jstack来查找那个线程此时所处的堆栈,确定问题发生位置。
各工具详细介绍
jstack
全称: JVM Stack Trance
作用: 查看某个java进程的堆栈情况, 可用于确认死锁、IO等待、死循环等问题。
命令用法:
- jstack pid
- 查看死锁例子如下图,找到wait的lock和已被锁的lock
- 查看等待IO例子:
jstat
全称:
作用:查看进程中内存使用情况,但只能给出一些简单统计数据
- 统计加载了多少类以及占用空间 jstat -class pid
- 统计编译了多少文件 jstat -compiler 10
- jstat -gcutil {pid} 2000 可以每隔2秒,对pid进程打印内存使用统计信息。
gcutil
的输出如下
Column | Description |
---|---|
S0 | 第0个survivor(幸存者)使用的百分比 |
S1 | 第1个survivor(幸存者)使用的百分比 |
E | Eden新生代内存 |
O | Old老年代内存 |
P/M | PermGen/MetaSpace的内存使用百分比 |
YGC | 程序启动以来Young GC发生的次数 |
YGCT | 程序启动以来Young GC总用时(s) |
FGC | 程序启动以来Full GC发生的次数 |
FGCT | 程序启动以来Full GGC总用时(s) |
GCT | 程序启动以来GC总用时(s) |
Q:里面哪个百分比如果长期处于99%-100%会有OMM风险?(OutOfMemoryError)
A:如果E和O即新生代、老年代内存区一直都处于满的状态,则很有可能会引发OMM风险。就像下面这个。
jmap
全称: JVM Memory Map
作用:生成进程的内存堆快照
当需要看一下进程里是什么东西占用了过多内存时, 可以用jmap打印一下堆快照。
命令用法:
- 打印堆快照: jmap -dump:file=./dumpfile.dump 进程pid
- 查看特定类所占用的情况: jmap -histo:live 进程pid | grep 类名
Q: 用jmap检查内存泄漏实例
我分了3次,每个1h调用jmap查看进程的内存实例,查看该时刻各对象数量
第一次查看情况如下:
第二次隔了2各小时,查看情况如下:
请问哪个对象可能有内存泄漏风险?
A:ObjectA可能有泄露, 因为他的对象数量增加最快,说明对象一直在增加且很多无法进行gc释放。
jhat
全称: JVM Heap Analysis Tool
和jmap配合, 可以解析jmap生成的堆快照, 支持生成1个web进程供我们分析和查看。
命令用法:
jhat -J-Xmx515M dumpfile.dump
此时就会启动1个webServer,然后我们去访问就行了
jdb
全称:Java Debugger
作用:用来对core文件和正在运行的Java进程进行实时地调试,类似于c++里的gdb
常见用法:
- 启动进程并调试: jdb -classpath . Test
- 至二级调试某进程: jdb -attach 8000 -sourcepath /Users/wefit/Development/study/java/jtest/src/
jcmd
作用:多功能的工具,可以用它来导出堆、查看Java进程、导出线程信息、执行GC、还可以进行采样分析,可以理解为1个性能调优时用的工具。
常见命令:
- 查看 当前机器上所有的 jvm 进程信息: jcmd -l
- 查看指定进程的性能统计信息: jcmd pid PerfCounter.print
- 列出当前运行的 java 进程可以执行的操作: jcmd PID help
- 查看线程堆栈信息: jcmd PID Thread.print
- 查看堆内存信息: jcmd PID GC.heap_dump FILE_NAME
jps
简单记法: JVM process status
全名:Java Virtual Machine Process Status Tool
作用: 显示?当前系统用户?的?所有?Java进程情况及其进程号
常用命令:
- 查看进程jvm参数: jps -v
- 输出程序main class的完整package名或程序的jar文件完整路径名: jps -l
- 输出传递给main方法的参数: jps -m
jinfo
jvm infomation
作用:和jps功能类似, 但是支持根据指定pis查看指定进程
- 可以查看JVM参数、系统参数、调整jvm参数
- 但不支持查看java程序的内存使用情况
javap
把java字节码文件反汇编为Java源码文件。
javac
javac是java编译工具
IDEA-DEBUG功能
idea的debug功能是怎么实现的? 为什么可以通过Evaluate 进行条件判断的?按以下问题逐个解答
完整详解见IDEA的debug功能,背后的原理是怎样的?
Q: idea的debug中可以evaluate修改进程行为,是通过什么修改的?
A:
ASM框架——动态修改类、方法,甚至可以重新定义类,连 CGLib 底层都是用 ASM 实现的。 访问者模式。需要实现visitMethod()/visitAnnotation()
Q: 实现了ASM框架,就会自动支持修改吗?
A:
不会自动支持, 需要使用 instrument 的类修改功能,我们需要实现它的 ClassFileTransformer 接口定义一个类文件转换器。它唯一的一个 transform() 方法会在类文件被加载时调用,在 transform 方法里,我们可以对传入的二进制字节码进行改写或替换,生成新的字节码数组后返回,JVM 会使用 transform 方法返回的字节码数据进行类的加载。
Q: 怎么才能让 JVM 能够调用我们提供的类转换器呢
A:
- JVM TI 通过事件机制,通过接口注册各种事件勾子,在 JVM 事件触发时同时触发预定义的勾子,以实现对各个 JVM 事件的感知和反应。
- Agent 是 JVM TI 实现的一种方式
- Java 的调试体系 jdpa 组成,从高到低分别为 jdi->jdwp->jvmti,我们通过 JDI 接口发送调试指令,而 jdwp 就相当于一个通道,帮我们翻译 JDI 指令到 JVM TI,最底层的 JVM TI 最终实现对 JVM 的操作。
- debug时要添加参数 -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:3333,而 -agentlib 选项就指定了我们要加载的 Java Agent,jdwp 是 agent 的名字
Q: 那你讲一下我要自己实现一个可修改代码的agent的话该怎么做?
A:
实现一个Agent
- 实现入口类agentmain(String args, Instrumentation inst)
- 在main里给inst添加转化方法addTransformer(自定义Transformer())
- 再对需要的类进行转化inst.retransformClasses(TransformTarget.class)。
- 实现自定义Transformer, 里面需要实现一个ClassVisitor 访问者模式,有类似visitMethod的方法实现
- 使用Attacher 将agent动态加载到目标jvm上。
VirtualMachine vm = VirtualMachine.attach("34242"); // 目标 JVM pid
vm.loadAgent("/path/to/agent.jar")
JDK性能监控和调优工具
有阿里的Arthas、 商业化的jprofiler
能进行CPU分析、方法耗时分析、GC活动分析、实时堆内容分析、 采样时间内的方法火焰图等
Q: 阿里的Arthas、 商业化的jprofiler 他们能监控的原理是什么?
- 开发者可以在main函数执行之后再启动自己的Instrument应用,入口是agentmain函数。arthas就是通过这个实现的。利用-javaagent参数进行instrument的初始化,可以通过这个入口修改class
之后就可以通过addTransformer,retransformClasses,redefineClasses等方式对字节码进行增强和热替换了。 - 修改字节码也需要一套框架,不然自己重写太蛮烦了。ASM是一个Java字节码操作框架,用来动态生成class或者增强class,cglib的底层就是它,arthas也是通过它实现对class的增强的。
- Arthas增强功能的核心是Enhancer和AdviceWeaver这两个类,对方法进行Aop织入,达到watch,trace等效果。
- 还要提供一个启动端口连接的功能。JVMTI(JVM Tool Interface)是Java虚拟机所提供的native接口,提供了可用于debug和profiler的能力,是实现调试器和其他运行态分析工具的基础,Instrument就是对它的封装。
通过JDI接口进行交互调试,attach端口建立连接。
JDK可视化工具
jconsole
可监控jvm,即可监控本地jvm也可监控远程jvm,管理应用程序,可以检查死锁等诸多问题。
jvisualvm
- jvisualvm可以监控远程服务器的运行状态
- 可以在java程序运行起来后再运行, 通过某些协议连接到java进程中。
- 运行时, 可以不需要配置配置环境、虚拟机参数等。
本博客文章除特别声明外,均可自由转载与引用,转载请标注原文出处:http://www.yelbee.top/index.php/archives/209/