JAVA垃圾回收笔记

一、分析GC日志

/**
 * @author : Hejinsheng
 * @date : 2019/1/18 0018
 * @Description: 模拟FULL GC/YOUNG GC
 * -Xms100M -Xmx100M -Xmn32m -XX:SurvivorRatio=8 -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
 */
public class GCTest {

    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        for(int i=0;;i++){
            System.out.println(i);
            list.add(new byte[1024]);
        }
    }
}

打印的GC信息

[Full GC (Ergonomics) [PSYoungGen: 26624K->26623K(29696K)] [ParOldGen: 69631K->69630K(69632K)] 96255K->96253K(99328K), [Metaspace: 3298K->3298K(1056768K)], 0.0200149 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
[Full GC (Ergonomics) [PSYoungGen: 26624K->26623K(29696K)] [ParOldGen: 69631K->69631K(69632K)] 96255K->96255K(99328K), [Metaspace: 3298K->3298K(1056768K)], 0.0177546 secs] [Times: user=0.08 sys=0.00, real=0.02 secs]
[Full GC (Allocation Failure) [PSYoungGen: 26623K->26623K(29696K)] [ParOldGen: 69631K->69613K(69632K)] 96255K->96236K(99328K), [Metaspace: 3298K->3298K(1056768K)], 0.0466197 secs] [Times: user=0.03 sys=0.00, real=0.05 secs]

1. 最前面的数字217.539:代表GC发生的时间,从虚拟机启动开始算起

2. GC日志开头的[GC和FULL GC]说明这次垃圾收集的停顿类型,而不是区分新生代和老年代的。

FULL GC : 说明这次GC是发生了线程停顿Stop-The-World,如果是System.gc()方法所触发的收集,,那么在这里将显示[Full GC (System)

3. [DefNew,[Tenured,[Perm表示GC发生的区域,这里显示的区域名称和使用的垃圾收集器是密切相关的

1>在Serial收集器中新生代名为Default New Generation ,显示就是DefNew

2>垃圾收集器ParNew中新生代名称就会变为[Parnew,意思为Parallel New Generation 

3>如果采用Parrallel Scavenge收集器,那么它配套的新生代名称为PSYongGen

老年代和永久代同理,名称由垃圾收集器决定

4.[DefNew: 102646K->10770K(102976K), 0.0415902 secs] 239776K->153169K(331528K), 0.0416785 secs] [Times: user=0.03 sys=0.02, real=0.04 secs] 就这段而言,

1>方括号内部102646K->10770K(102976K)的含义是GC前改内存区域已使用内存->GC后改内存区域使用容量(该内存区域总容量)

2>方括号外 239776K->153169K(331528K)表示GC前java堆已使用容量->GC后java堆已使用容量(java堆总容量)

3>在往后时间表示该内存区域gc清理用的时间

4>[Times: user=0.03 sys=0.02, real=0.04 secs]

这里面的user、sys和real与linux的time命令所输出的时间含义一致,分别表示用户态消耗的CPU时间、内核态消耗的CPU事件和操作从开始到结束经历的墙钟时间

墙钟时间和CPU时间的区别是,墙钟时间包括各种非运算的等待耗时(i/o,线程阻塞),而CPU时间不包括这些,但是如果是多核,

多线程会叠加这些CPU时间,此时user或sys时间超过real时间完全是正常的

 

二、获取堆转储的几种方式

Heap Dump 是 Java进程所使用的内存情况在某一时间的一次快照。以文件的形式持久化到磁盘中。
Heap Dump的格式有很多种,而且不同的格式包含的信息也可能不一样。但总的来说,Heap Dump一般都包含了一个堆中的Java Objects, Class等基本信息。同时,当你在执行一个转储操作时,往往会触发一次GC,所以你转储得到的文件里包含的信息通常是有效的内容(包含比较少,或没有垃圾对象了) 。

Heap Dump 包含的信息

所有的对象信息
  对象的类信息、字段信息、原生值(int, long等)及引用值
所有的类信息
  类加载器、类名、超类及静态字段
垃圾回收的根对象
  根对象是指那些可以直接被虚拟机触及的对象
线程栈及局部变量
  包含了转储时刻的线程调用栈信息和栈帧中的局部变量信息
Heap Dump 获取方式

1. 使用 jmap 命令生成 dump 文件

jmap -dump:live,format=b,file=d:\dump\heap.hprof <pid>

2. 使用 jcmd 命令生成 dump 文件

jcmd <pid> GC.heap_dump d:\dump\heap.hprof

3. 使用 JVM 参数获取 dump 文件

  1. -XX:+HeapDumpOnOutOfMemoryError
  当OutOfMemoryError发生时自动生成 Heap Dump 文件。

  这可是一个非常有用的参数,因为当你需要分析Java内存使用情况时,往往是在OOM(OutOfMemoryError)发生时。
  2. -XX:+HeapDumpBeforeFullGC
  当 JVM 执行 FullGC 前执行 dump。

  3. -XX:+HeapDumpAfterFullGC
  当 JVM 执行 FullGC 后执行 dump。

  4. -XX:+HeapDumpOnCtrlBreak
  交互式获取dump。在控制台按下快捷键Ctrl + Break时,JVM就会转存一下堆快照。

  5. -XX:HeapDumpPath=d:\test.hprof
  指定 dump 文件存储路径。

  注意:JVM 生成 Heap Dump 的时候,虚拟机是暂停一切服务的。如果是线上系统执行 Heap Dump 时需要注意。

分析 工具:jdk 自带的工具 jvisualvm、Eclipse memory analyzer(jmat)、JProfiler 等。

三、jvisualvm使用

1、点击文件-装入,载入dump下来的文件

 

2、点击类选项卡

 

3、根据上图分析实例数或占用大小比例较高的类,右键 “在实例视图中显示”,如

找到可能发生内存泄漏或内存溢出的根对象

 

posted @ 2019-01-17 15:04  hejinsheng  阅读(198)  评论(0编辑  收藏  举报