9、学会查看GC日志

要查看gc日志,那么首先得把gc日志进行输出,在JVM启动的时候添加参数:

-XX:+PrintGCDetails 打印GC日志细节

-XX:+PrintGCTimeStamps 打印GC日志时间

-Xloggc:gc.log 将GC日志输出到指定的磁盘文件上去,这里会把gc.log输出到项目根路径

然后JVM在运行过程中如果发生gc,那么将会把gc日志输出到gc.log中。

现在我们手动模拟一下Young GC的发生,然后查看gc日志。

配置JVM参数:

-XX:NewSize=5242880

-XX:MaxNewSize=5242880

-XX:InitialHeapSize=10485760

-XX:MaxHeapSize=10485760

-XX:SurvivorRatio=8

-XX:MaxTenuringThreshold=15

-XX:PretenureSizeThreshold=10485760

-XX:+UseParNewGC

-XX:+UseConcMarkSweepGC

-XX:+PrintGCDetails

-XX:+PrintGCTimeStamps

-Xloggc:gc.log

这里配置了新生代大小为5M,堆内存大小为10M,那么老年代大小就是5M。SurvivorRatio=8,那么Eden区就是Survivor区的8倍,所以Eden区占4M,两个Survivor都是占0.5M。MaxTenuringThreshold=15,那么新生代对象只有达到15岁才会进入老年代。PretenuringSizeThreshold等于10M,那么只有大于10M的对象才能直接在老年代分配。使用ParNew + CMS垃圾回收器。

写一个简单的main方法,来运行:

public static void main(String[] args) {
    byte[] array = new byte[1024 * 1024];
    array = new byte[1024 * 1024];
    array = new byte[1024 * 1024];
    array = null;

    //触发Young GC
    byte[] array1 = new byte[2 * 1024 * 1024];

}

在上面的代码中,我们可以推测一下GC的具体发生过程。

如果是在IDEA中,那么配置JVM参数可以点开Edit Configurations:

 勾选 Add VM options,然后在VM options的框中输入对应的JVM启动参数,然后运行main方法。

在项目的根路径下,就可以看到一个gc.log,点进去查看:

CommandLine flags: -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:MaxNewSize=5242880 -XX:NewSize=5242880 -XX:OldPLABSize=16 -XX:PretenureSizeThreshold=10485760 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:-UseLargePagesIndividualAllocation -XX:+UseParNewGC


0.383: [GC (Allocation Failure) 0.384: [ParNew: 3543K->512K(4608K), 0.0024598 secs] 3543K->1828K(9728K), 0.0026607 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.386: [GC (Allocation Failure) 0.387: [ParNew: 2627K->0K(4608K), 0.0015255 secs] 3943K->1828K(9728K), 0.0015985 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]


Heap
 par new generation   total 4608K, used 2089K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
  eden space 4096K,  51% used [0x00000000ff600000, 0x00000000ff80a558, 0x00000000ffa00000)
  from space 512K,   0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)
  to   space 512K,   0% used [0x00000000ffa80000, 0x00000000ffa80000, 0x00000000ffb00000)
 concurrent mark-sweep generation total 5120K, used 1828K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 3101K, capacity 4620K, committed 4864K, reserved 1056768K
  class space    used 327K, capacity 392K, committed 512K, reserved 1048576K

第一段内容中输出了JVM启动参数,里面都是按照我们配置的参数来的,还有一些别的默认参数。

第二段内容中可以看到进行了两次GC。

0.383: [GC (Allocation Failure) 0.384: [ParNew: 3543K->512K(4608K), 0.0024598 secs] 3543K->1828K(9728K), 0.0026607 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.386: [GC (Allocation Failure) 0.387: [ParNew: 2627K->0K(4608K), 0.0015255 secs] 3943K->1828K(9728K), 0.0015985 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

JVM运行的第0.383秒,发生Allocation Failure,就是给对象分配内存的时候内存空间不够了,所以在第0.384秒的时候,使用ParNew垃圾回收器进行了Young GC。

[ParNew: 3543K->512K(4608K),0.0024598 secs] : 新生代的总内存大小为4608KB(4M的Eden区 加上了 0.5M的 Survivor From区,一共是4.5M,即4608M);Young GC之前,新生代占用内存大小为3543KB(三个1M的数组,加上471KB的“未知内容”);Young GC之后,剩余了512KB(“未知内容”)。

3543K->1828K(9728K) : 整个堆内存大小为9728KB(即4M的Eden区加上0.5M的Survivor区加上5M的老年代大小,9.5M,即9728KB)。在Young GC之前,堆内存共有3543KB内存被占用(三个1M的数组,加上471KB的“未知内容”);在Young GC之后,堆内存共有1828KB。

第三段内容输出了Young GC之后的堆内存使用快照:

Heap
 par new generation   total 4608K, used 2089K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
  eden space 4096K,  51% used [0x00000000ff600000, 0x00000000ff80a558, 0x00000000ffa00000)
  from space 512K,   0% used [0x00000000ffa00000, 0x00000000ffa00000, 0x00000000ffa80000)
  to   space 512K,   0% used [0x00000000ffa80000, 0x00000000ffa80000, 0x00000000ffb00000)
 concurrent mark-sweep generation total 5120K, used 1828K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 3101K, capacity 4620K, committed 4864K, reserved 1056768K
  class space    used 327K, capacity 392K, committed 512K, reserved 1048576K

可以看到新生代占用了2098KB(一个2M的数组,还有一点“未知内容”);Eden区被占用了51%,Survivor From和Survivor To使用率为0%,CMS管理的老年代被使用了1828KB。

1、JVM是如何工作的?_jerry_dyy的博客-CSDN博客_jvm是如何运行的

2、JVM的类加载机制_jerry_dyy的博客-CSDN博客

3、JVM内存区域划分_jerry_dyy的博客-CSDN博客_jvm的内存区域划分

4、JVM垃圾回收机制_jerry_dyy的博客-CSDN博客

5、JVM分代模型--新生代 的垃圾回收_jerry_dyy的博客-CSDN博客_jvm新生代划分

6、JVM分代模型--老年代 的垃圾回收_jerry_dyy的博客-CSDN博客

7、常见的垃圾回收器_jerry_dyy的博客-CSDN博客

8、JVM优化简介_jerry_dyy的博客-CSDN博客

9、学会查看GC日志_jerry_dyy的博客-CSDN博客

10、摸清JVM运行状况_jerry_dyy的博客-CSDN博客

11、摸清JVM对象分布_jerry_dyy的博客-CSDN博客

12、OOM简介_jerry_dyy的博客-CSDN博客

13、OOM模拟_jerry_dyy的博客-CSDN博客

  • 9
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值