JVM性能监控(垃圾回收)
应该关注的垃圾回收数据
使用那种垃圾回收机制
Java堆的大小
新生代和老年代的大小
永久代的大小
次收集(minor GC)用时多少
次收集(minor GC)的频率
次收集(minor GC)能回收多少空间
全收集(full GC)用时多少
全收集(full GC)的频率
一个并发垃圾回收周期能回收多少空间
垃圾回收前后的Java堆的使用情况
垃圾回收前后的新生代和老年代的使用情况
垃圾回收前后的永久代的使用情况
全收集(full GC)是由老年代还是永久代所出发的
应用是否显示的调用了System.gc()
垃圾回收报告
有两种不同的垃圾收集
次收集(minor GC):回收新生代的空间
全收集(full GC):回收老年代和永久代的空间
这里有一些例外 HotSpot VM 的全收集默认是回收新生代,老年代,永久代的空间。
关闭全收集是的新生代收集:
-XX:-ScavengeBeforeFullGC
-XX:+PrintGCDetails
虽然说-verbose:gc可能是最常用的gc报告命令,但-XX:+PrintGCDetails能收集更多的垃圾收集信息。
[GC [PSYoungGen: 297694K->43634K(305856K)]
297766K->50890K(1004928K), 0.2877270 secs]
[Times: user=0.34 sys=0.06, real=0.29 secs]
把它分解,看看每一部分是什么意思
[GC [<collector name>: <occupancy at start> -> <occupancy at end> (<total size>)]
<full heap occypancy at start> -> <full heap occupancy at end>(<total heap size>), <pause time> secs]
[Time: 经过的cpu时间]
PSYoungGen表示正在使用的是为吞吐量优化的多线程的新生代垃圾收集。使用 –XX:+UseParallelGC 启用或使用 –XX:+UseParallelOldGC 自动打开。 其他可能的收集器有ParNew(CMS中使用的多线程新生代收集器),DefNew(单线程的新生代收集器,由serial收集器使用)
[Full GC
[PSYoungGen: 11456K->0K(110400K)]
[PSOldGen: 651536K->58466K(655360K)]
662992K->58466K(765760K)
[PSPermGen: 10191K->10191K(22528K)],
1.1178951 secs]
[Times: user=1.01 sys=0.00, real=1.12 secs]
把它分解,看看每一部分是什么意思
[Full Gc
[<collector name>: <occupancy at start> -> <occupancy at end>(<total size>)]
[<collector name>: <occupancy at start> -> <occupancu at end>(<total size>)]
<heap occupancy at start> -> <heap occupancy at end>(<total heap size>)
[<collector name>: <occupancy at start> -> <occupancu at end>(<total size>)]
elapsed time for the garbage collection]
[Time: 经过的cpu时间]
当使用concurrent garbage collector(CMS)这些输出会不一样 启用CMS
-XX:+UseConcMarkSweepGC
[GC
[ParNew: 2112K->64K(2112K), 0.0837052 secs]
16103K->15476K(773376K), 0.0838519 secs]
[Times: user=0.02 sys=0.00, real=0.08 secs]
CMS整个垃圾回收周期日志
[GC
[1 CMS-initial-mark: 13991K(773376K)] 14103K(773376K), 0.0023781 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-mark-start]
[GC
[ParNew: 2077K->63K(2112K), 0.0126205 secs]
17552K->15855K(773376K), 0.0127482 secs]
[Times: user=0.01 sys=0.00, real=0.01 secs]
[CMS-concurrent-mark: 0.267/0.374 secs]
[Times: user=4.72 sys=0.01, real=0.37 secs]
[GC
[ParNew: 2111K->64K(2112K), 0.0190851 secs]
17903K->16154K(773376K), 0.0191903 secs]
[Times: user=0.01 sys=0.00, real=0.02 secs]
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.044/0.064 secs]
[Times: user=0.11 sys=0.00, real=0.06 secs]
[CMS-concurrent-abortable-preclean-start]
[CMS-concurrent-abortable-clean] 0.031/0.044 secs]
[Times: user=0.09 sys=0.00, real=0.04 secs]
[GC
[YG occupancy: 1515 K (2112K)
[Rescan (parallel) , 0.0108373 secs]
[weak refs processing, 0.0000186 secs]
[1 CMS-remark: 16090K(20288K)]
17242K(773376K), 0.0210460 secs]
[Times: user=0.01 sys=0.00, real=0.02 secs]
[GC
[ParNew: 2112K->63K(2112K), 0.0716116 secs]
18177K->17382K(773376K), 0.0718204 secs]
[Times: user=0.02 sys=0.00, real=0.07 secs]
[CMS-concurrent-sweep-start]
[GC
[ParNew: 2111K->63K(2112K), 0.0830392 secs]
19363K->18757K(773376K), 0.0832943 secs]
[Times: user=0.02 sys=0.00, real=0.08 secs]
[GC
[ParNew: 2111K->0K(2112K), 0.0035190 secs]
17527K->15479K(773376K), 0.0036052 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-sweep: 0.291/0.662 secs]
[Times: user=0.28 sys=0.01, real=0.66 secs]
[GC
[ParNew: 2048K->0K(2112K), 0.0013347 secs]
17527K->15479K(773376K), 0.0014231 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.016/0.016 secs]
[Times: user=0.01 sys=0.00, real=0.02 secs]
[GC
[ParNew: 2048K->1K(2112K), 0.0013936 secs]
17527K->15479K(773376K), 0.0014814 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
一个CMS周期是由CMS-initial-mark开始到CMS- concurrent-reset结束。
CMS-concurrent-mark表示标记阶段的结束
CMS-concurrent-preclean和CMS-concurrent-abortable-preclean表示可以并发的完成再标记工作
CMS-remark表示再标记阶段
CMS-concurrent-sweep表示并发清除阶段的结束,这个阶段清除那些被标记为不可达的对象
初始标记需要暂停很短的时间然后进入并发阶段。
重新标记的暂停时间取决于具体的应用情况。(如果对象修改的频繁就需要更久的时间)
需要重点关心的是CMS-concurrent-sweep-start和CMS-concurrent-sweep这两个阶段的java堆的回收情况
如果并发清扫阶段只回收了很少的内存,这可能是由:
CMS只找到很少的可回收的对象
对象已经进入老年代
无论哪一种情况,JVM都需要调优了
-XX:+PrintGCDetails
打印垃圾回收时间,格式为YYYY-MM-DD-T-HH-MM-SS.mmm-TZ
-Xloggc
把GC信息写入文件.用法: -Xloggc:<filename>
-XX:+PrintGCApplicationConcurrentTime
safepoint操作之间的时间间隔
-XX:+PrintGCApplicationStoppedTime
GC所暂停线程的时间
锁竞争
jstack
”Read Thread-33” prio=6 tid=0x02b1d400 nid=0x5c0 runnable
[0x0424f000..0x0424fd94]
java.lang.Thread.State: RUNNABLE
at Queue.dequeue(Queue.java:69)
- locked <0x22e88b10> (a Queue)
at ReadThread.getWorkItemFromQueue(ReadThread.java:32)
at ReadThread.run(ReadThread.java:23)
”Writer Thread-29” prio=6 tid=0x02b13c00 nid=0x3cc waiting for monitor
entry [0x03f7f000..0x03f7fd94]
java.lang.Thread.State: BLOCKED (on object monitor)
at Queue.enqueue(Queue.java:31)
- waiting to lock <0x22e88b10> (a Queue)
at WriteThread.putWorkItemOnQueue(WriteThread.java:54)
at WriteThread.run(WriteThread.java:47)
”Writer Thread-26” prio=6 tid=0x02b0d400 nid=0x194 waiting for monitor
entry [0x03d9f000..0x03d9fc94]
java.lang.Thread.State: BLOCKED (on object monitor)
at Queue.enqueue(Queue.java:31)
- waiting to lock <0x22e88b10> (a Queue)
at WriteThread.putWorkItemOnQueue(WriteThread.java:54)
at WriteThread.run(WriteThread.java:47)
”Read Thread-23” prio=6 tid=0x02b08000 nid=0xbf0 waiting for monitor entry
[0x03c0f000..0x03c0fb14]
java.lang.Thread.State: BLOCKED (on object monitor)
at Queue.dequeue(Queue.java:55)
- waiting to lock <0x22e88b10> (a Queue)
at ReadThread.getWorkItemFromQueue(ReadThread.java:32)
at ReadThread.run(ReadThread.java:23)
Read Thread-33 已获取locked <0x22e88b10>
其它都在waiting to lock <0x22e88b10> (a Queue).
blog comments powered by Disqus