java之GC日志该怎么看

1.编写程序

package com.lcc.jdk.test.gc;

public class MainTest {
    public  static void main(String[] args) throws Throwable {
        System.out.println("我在活着。。。。");
        System.gc();
        System.out.println("我要死了。。。。");
    }
}

2.设置参数

打印到日志文件

mac下

-XX:+PrintGCDetails -Xloggc:/Users/lcc/IdeaProjects/JdkSource/gc.log

java之GC日志该怎么看_第1张图片

windows下

-XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:d:/GClogs/tomcat6-gc.log

注意:可能会提示PrintGCTimeStamps找不到,我去掉了

2.2 打印到控制台

-Xms20M -Xmx20M -Xmn10M -verbose:gc -XX:+PrintGCDetails -XX:SurvivorRatio=8

2.3 输出时间

-XX:+PrintGCDateStamps -XX:+PrintGCDetails 

2.4 参数总结

-XX:+PrintGC 输出GC日志
-XX:+PrintGCDetails 输出GC的详细日志
-XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800-XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
-Xloggc:../logs/gc.log 日志文件的输出路径

2.5 JVM参数

分析gc日志后,经常需要调整jvm内存相关参数,常用参数如下

-Xms:初始堆大小,默认为物理内存的1/64(<1GB);默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%
时,JVM就会增大堆直到-Xmx的最大限制 

-Xmx:最大堆大小,默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小
限制 

-Xmn:新生代的内存空间大小,注意:此处的大小是(eden+ 2 survivor space)。与jmap -heap中显示的New
 gen是不同的。整个堆大小=新生代大小 + 老生代大小 + 永久代大小。 在保证堆大小不变的情况下,增大新生代后,
 将会减小老生代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

-XX:SurvivorRatio:新生代中Eden区域与Survivor区域的容量比值,默认值为8。两个Survivor区与一个Eden的比值为2:8,一个Survivor区占整个年轻代的1/10。 

-Xss:每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。应根据应用的线程所
需内存大小进行适当调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是
有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用, 如果栈不是很深, 应该是128k够用的,大的应
用建议使用256k。这个选项对性能影响比较大,需要严格的测试。和threadstacksize选项解释很类似,官方文档似乎
没有解释,在论坛中有这样一句话:”-Xss is translated in a VM flag named ThreadStackSize”一般设置这
个值就可以了。 

-XX:PermSize:设置永久代(perm gen)初始值。默认值为物理内存的1/64
-XX:MaxPermSize:设置持久代最大值。物理内存的1/4

java之GC日志该怎么看_第2张图片

Ratio

java之GC日志该怎么看_第3张图片

3.GC日志实例

参数:

-XX:+PrintGCDateStamps -XX:+PrintGCDetails 

日志

我在活着。。。。
2018-06-15T10:44:26.630-0800: [GC (System.gc()) [PSYoungGen: 2673K->496K(38400K)] 2673K->504K(125952K), 0.0010649 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
2018-06-15T10:44:26.631-0800: [Full GC (System.gc()) [PSYoungGen: 496K->0K(38400K)] [ParOldGen: 8K->402K(87552K)] 504K->402K(125952K), [Metaspace: 3300K->3300K(1056768K)], 0.0066154 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
我要死了。。。。
Heap
 PSYoungGen      total 38400K, used 1664K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
  eden space 33280K, 5% used [0x0000000795580000,0x00000007957201b0,0x0000000797600000)
  from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
  to   space 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
 ParOldGen       total 87552K, used 402K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
  object space 87552K, 0% used [0x0000000740000000,0x0000000740064ab8,0x0000000745580000)
 Metaspace       used 3312K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 369K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

解释之前先看看:
JVM体系
JVM经典模式
GC常见的算法

  1. PSYoungGen:表示新生代,这个名称由收集器决定。PS是Parallel Scavenge收集器的缩写,它配套的新生代称为PSYoungGen,新生代又分化eden space、from space和to space这三部分
  2. ParOldGen:Parallel Scavenge收集器配套的老年代
  3. Metaspace: Parallel Scavenge收集器配套的永久代
  4. total & used:总的空间和用掉的空间

如果收集器为ParNew收集器,新生代为ParNew,Parallel New Generation
如果收集器是Serial收集器,新生代为DefNew,Default New Generation
这里的收集器是Parallel Scavenge。

可以看到上面有两种GC类型:GC(第二行)和Full GC(第三行),有Full表示这次GC是发生了Stop-The-World的。

新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度非常快。

老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC,Major GC的速度一般会比Minor GC慢10倍以上。

3.1 Major GC

2018-06-15T10:44:26.630-0800: [GC (System.gc()) [PSYoungGen: 2673K->496K(38400K)] 2673K->504K(125952K), 0.0010649 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

上面方括号内部的[PSYoungGen: 2673K->496K(38400K)],表示

GC前该内存区域已使用容量->GC后该内存区域已使用容量,后面圆括号里面的38400K为该内存区域的总容量。

方括号外面的 2673K->504K(125952K), 0.0010649 secs],表示

GC前Java堆已使用容量->GC后Java堆已使用容量,后面圆括号里面的125952K为Java堆总容量。   PSYoungGen耗时

[Times: user=0.00 sys=0.00, real=0.00 secs]分别表示

用户消耗的CPU时间   内核态消耗的CPU时间     操作从开始到结束所经过的墙钟时间(Wall Clock Time)

user是用户态耗费的时间,sys是内核态耗费的时间,real是整个过程实际花费的时间。user+sys是CPU时间,每个CPU core单独计算,所以这个时间可能会是real的好几倍。

CPU时间和墙钟时间的差别是,墙钟时间包括各种非运算的等待耗时,例如等待磁盘I/O、等待线程阻塞,而CPU时间不包括这些耗时。

3.2 Full GC

2018-06-15T10:44:26.631-0800: [Full GC (System.gc()) [PSYoungGen: 496K->0K(38400K)] [ParOldGen: 8K->402K(87552K)] 504K->402K(125952K), [Metaspace: 3300K->3300K(1056768K)], 0.0066154 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 

从左到右分别为

[GC类型 (System.gc()) [Young区: GC前Young的内存占用->GC后Young的内存占用(Young区域总大小)] [old老年代: GC前Old的内存占用->GC后Old的内存占用(Old区域总大小)] GC前堆内存占用->GC后堆内存占用(JVM堆总大小), [永久代区: GC前占用大小->C后占用大小(永久代区总大小)], GC用户耗时] [Times:用户耗时 sys=系统时间, real=实际时间] 

3.3 规律

[名称:gc前内存占用-> gc后内存占用(该区内存总大小)]

4.GC日志的离线分析

可以使用一些离线的工具来对GC日志进行分析,比如sun的gchisto( https://java.net/projects/gchisto),gcviewer( https://github.com/chewiebug/GCViewer ),这些都是开源的工具,用户可以直接通过版本控制工具下载其源码,进行离线分析。

必看:
https://www.jianshu.com/p/fd1d4f21733a
https://www.jianshu.com/p/088d71f20a47
https://www.jianshu.com/p/5bad514071ab
https://www.jianshu.com/p/8eabaf631d15
https://www.jianshu.com/p/26f95965320e
https://www.jianshu.com/p/fd1d4f21733a
https://www.jianshu.com/p/dbaabe4554b6

你可能感兴趣的:(语言-JVM)