概述
某天系统响应变慢需要分析原因,也许我们马上会想起java core分析三板斧,top、pid等等定位到线程使用jstack命令输出线程堆栈。那么如果是内存回收不掉的情况呢?也许你的系统已配置-XX HeapDumOnMemoryError,
-XX HeapDumpPath=XXX,但是一旦如果你没设置而且系统并没内存溢出,只是响应慢,回收不理想呢?这时候用什么命令呢?当然这个可以现查现用,但如果是在面试呢?也许你知道但是不记得了,但这个简单问题很可能直接会让面试官认为你没做过或者不知道,所以简单整理一下。
总结
一、jmap命令解析与使用
jmap -heap [pid] 查询内存使用情况
[root@fengniaoweb ~]# jmap -heap 2865
Attaching to process ID 2865, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
using thread-local object allocation.
Parallel GC with 4 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 268435456 (256.0MB)
NewSize = 42991616 (41.0MB)
MaxNewSize = 89128960 (85.0MB)
OldSize = 87031808 (83.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 = 88080384 (84.0MB)
used = 86317448 (82.31873321533203MB)
free = 1762936 (1.6812667846679688MB)
97.99849192301433% used
From Space:
capacity = 524288 (0.5MB)
used = 32768 (0.03125MB)
free = 491520 (0.46875MB)
6.25% used
To Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
PS Old Generation
capacity = 179306496 (171.0MB)
used = 74843440 (71.37626647949219MB)
free = 104463056 (99.62373352050781MB)
41.74050671315332% used
26363 interned Strings occupying 3142776 bytes.
要注意的是在使用CMS GC 情况下,jmap -heap的执行有可能会导致JAVA 进程挂起
jmap -histo [pid] 查看JVM堆中对象详细占用情况
// 限于篇幅仅粘贴示例
3007: 1 16 [Lorg.aspectj.weaver.ast.Var;
3008: 1 16 [Lorg.aspectj.weaver.patterns.AnnotationTypePattern;
3009: 1 16 [Lorg.aspectj.weaver.patterns.BindingPattern;
3010: 1 16 [Lorg.aspectj.weaver.tools.PointcutParameter;
3011: 1 16 [Lorg.springframework.web.context.request.async.CallableProcessingInterceptor;
3012: 1 16 [Lorg.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
3013: 1 16 [Lsun.reflect.annotation.TypeAnnotation$LocationInfo$Location;
3014: 1 16 [[Lorg.aspectj.weaver.AnnotationAJ;
3015: 1 16 com.alibaba.fastjson.parser.deserializer.CharArrayDeserializer
3016: 1 16 com.alibaba.fastjson.parser.deserializer.ClassDerializer
3017: 1 16 com.alibaba.fastjson.parser.deserializer.CollectionDeserializer
3018: 1 16 com.alibaba.fastjson.parser.deserializer.DateDeserializer
3019: 1 16 com.alibaba.fastjson.parser.deserializer.DateFormatDeserializer
3020: 1 16 com.alibaba.fastjson.parser.deserializer.JSONArrayDeserializer
3021: 1 16 com.alibaba.fastjson.parser.deserializer.JSONObjectDeserializer
3022: 1 16 com.alibaba.fastjson.parser.deserializer.JavaObjectDeserializer
3023: 1 16 com.alibaba.fastjson.parser.deserializer.Jdk8DateCodec
3024: 1 16 com.alibaba.fastjson.parser.deserializer.MapDeserializer
3025: 1 16 com.alibaba.fastjson.parser.deserializer.NumberDeserializer
3026: 1 16 com.alibaba.fastjson.parser.deserializer.SqlDateDeserializer
3027: 1 16 com.alibaba.fastjson.parser.deserializer.StackTraceElementDeserializer
3028: 1 16 com.alibaba.fastjson.parser.deserializer.TimeDeserializer
3029: 1 16 com.alibaba.fastjson.parser.deserializer.TimestampDeserializer
jmap -dump:format=b,file=文件名 [pid]
[root@fengniaoweb home]# jmap -dump:format=b,file=heapsim 2865
Dumping heap to /home/heapsim ...
Heap dump file created
[root@fengniaoweb home]# ls
apollo heapsim
[root@fengniaoweb home]#
在当前目录下生成内存dump文件
二、内存快照分析工具
jhat java自带的内存快照分析工具 一般不常用,因为有本机内存限制,不易于分析大内存文件
eclipse Memory Analyzer
Eclipse 提供的一个用于分析JVM 堆Dump文件的插件。借助这个插件可查看对象的内存占用状况,引用关系,分析内存泄露等。
具体的分析过程不作为本文讨论重点,这里就不详细讨论了。
三、kill -3 [pid] 输出线程堆栈信息
当系统负载较高响应较慢的时候或者未安装jstack命令时可以使用该命令打印java进程堆栈信息。
如果项目通过Tomcat进行发布(普通的web项目),则对应的堆栈信息会打印在catalina.out文件中。
如果项目是基于SpringBoot并且使用nohup java -jar xxx.jar & 命令运行,则java堆栈信息会在jar包所在的nohup.out文件中。
注意:该命令并不会杀死jvm进程
[root@fengniaoweb logs]# kill -3 2865
// 在nohup文件中发现如下堆栈信息
"JDWP Event Helper Thread" #6 daemon prio=10 os_prio=0 tid=0x00007f80c818f000 nid=0xb3c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Transport Listener: dt_socket" #5 daemon prio=10 os_prio=0 tid=0x00007f80c818b800 nid=0xb3b runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f80c817f800 nid=0xb3a waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f80c814d800 nid=0xb39 in Object.wait() [0x00007f80cc16c000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000000f008a960> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f80c814a800 nid=0xb38 in Object.wait() [0x00007f80b1f31000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000f008a990> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=0 tid=0x00007f80c8141000 nid=0xb37 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f80c8021000 nid=0xb33 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f80c8022800 nid=0xb34 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f80c8024800 nid=0xb35 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f80c8026800 nid=0xb36 runnable
四、 jstack [pid] jvm自带的堆栈工具
通过该工具可以看到JVM 中线程的运行状况,包括锁等待,线程是否在运行,线程的所有堆栈信息
[root@fengniaoweb logs]# jstack 2865
Attaching to process ID 2865, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
Deadlock Detection:
No deadlocks found.
Thread 20440: (state = BLOCKED)
Thread 11659: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise)
- java.lang.ref.ReferenceQueue.remove(long) @bci=59, line=144 (Compiled frame)
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=165 (Compiled frame)
- org.apache.commons.httpclient.MultiThreadedHttpConnectionManager$ReferenceQueueThread.run() @bci=10, line=1122 (Interpreted frame)
Thread 10425: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise)
- java.lang.ref.ReferenceQueue.remove(long) @bci=59, line=144 (Compiled frame)
- com.mysql.jdbc.AbandonedConnectionCleanupThread.run() @bci=10, line=64 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=95, line=1149 (Interpreted frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=624 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)
Thread 10424: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Compiled frame; information may be imprecise)
- java.util.TimerThread.mainLoop() @bci=201, line=552 (Compiled frame)
- java.util.TimerThread.run() @bci=1, line=505 (Interpreted frame)
Thread 2866: (state = BLOCKED)
Thread 3079: (state = BLOCKED)
- java.lang.Thread.sleep(long) @bci=0 (Compiled frame; information may be imprecise)
- org.apache.coyote.AbstractProtocol$AsyncTimeout.run() @bci=10, line=1133 (Compiled frame)
- java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)
Thread 3078: (state = IN_NATIVE)
- sun.nio.ch.ServerSocketChannelImpl.accept0(java.io.FileDescriptor, java.io.FileDescriptor, java.net.InetSocketAddress[]) @bci=0 (Compiled frame; information may be imprecise)
- sun.nio.ch.ServerSocketChannelImpl.accept(java.io.FileDescriptor, java.io.FileDescriptor, java.net.InetSocketAddress[]) @bci=4, line=422 (Compiled frame)
- sun.nio.ch.ServerSocketChannelImpl.accept() @bci=130, line=250 (Compiled frame)
- org.apache.tomcat.util.net.NioEndpoint$Acceptor.run() @bci=88, line=455 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)
Thread 3077: (state = IN_NATIVE)
- sun.nio.ch.EPollArrayWrapper.epollWait(long, int, long, int) @bci=0 (Compiled frame; information may be imprecise)
- sun.nio.ch.EPollArrayWrapper.poll(long) @bci=18, line=269 (Compiled frame)
- sun.nio.ch.EPollSelectorImpl.doSelect(long) @bci=28, line=93 (Compiled frame)
- sun.nio.ch.SelectorImpl.lockAndDoSelect(long) @bci=37, line=86 (Compiled frame)
- sun.nio.ch.SelectorImpl.select(long) @bci=30, line=97 (Compiled frame)
- org.apache.tomcat.util.net.NioEndpoint$Poller.run() @bci=55, line=793 (Compiled frame)
- java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)
Thread 3076: (state = IN_NATIVE)
- sun.nio.ch.EPollArrayWrapper.epollWait(long, int, long, int) @bci=0 (Compiled frame; information may be imprecise)
- sun.nio.ch.EPollArrayWrapper.poll(long) @bci=18, line=269 (Compiled frame)
- sun.nio.ch.EPollSelectorImpl.doSelect(long) @bci=28, line=93 (Compiled frame)
- sun.nio.ch.SelectorImpl.lockAndDoSelect(long) @bci=37, line=86 (Compiled frame)
- sun.nio.ch.SelectorImpl.select(long) @bci=30, line=97 (Compiled frame)
- org.apache.tomcat.util.net.NioEndpoint$Poller.run() @bci=55, line=793 (Compiled frame)
- java.lang.Thread.run() @bci=11, line=748 (Interpreted frame)
关于jstack命令的详细讲解可以参考
https://www.cnblogs.com/xingzc/p/5778010.html
附加:
命令格式 top -Hp pid -d 1 -n 1
打印进程号为pid的进程所有子线程的cpu,内存等资源占用情况。
该命令结合线程堆栈可以分析线程资源占用问题