热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JVM:33如何查看JVM的FullGC日志

1.示例代码packagecom.webcode;publicclassDemo4{publicstaticvoidmain(String[]args){byte[]arr

1. 示例代码

package com.webcode; public class Demo4 { public static void main(String[] args){ byte[] array1 = new byte[4 * 1024 * 1024]; array1 = null; byte[] array2 = new byte[2 * 1024 * 1024]; byte[] array3 = new byte[2 * 1024 * 1024]; byte[] array4 = new byte[2 * 1024 * 1024]; byte[] array5 = new byte[128 * 1024]; byte[] array6 = new byte[2 * 1024 * 1024]; } }

2. GC日志

采用如下JVM参数来运行上述程序:

-XX:NewSize=10485760 -XX:MaxNewSize=10485760 -XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:PretenureSizeThreshold=3145728 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log

这里最关键的一个参数,是 “-XX:PretenureSizeThreshold=3145728” ,该参数设置大对象阈值为3MB,也就是超过3MB,就直接进入老年代。

运行之后的GC日志如下:

0.113: [GC (Allocation Failure) 0.113: [ParNew (promotion failed): 7256K->7953K(9216K), 0.0028080 secs]0.116: [CMS: 8194K->6805K(10240K), 0.0035630 secs] 11352K->6805K(19456K), [Metaspace: 2644K->2644K(1056768K)], 0.0068409 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Heap
 par new generation   total 9216K, used 2130K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  eden space 8192K,  26% used [0x00000000fec00000, 0x00000000fee14930, 0x00000000ff400000)
  from space 1024K,   0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
  to   space 1024K,   0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
 concurrent mark-sweep generation total 10240K, used 6805K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
 Metaspace       used 2651K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 286K, capacity 386K, committed 512K, reserved 1048576K

3. 日志分析

首先看如下代码:

byte[] array1 = new byte[4 * 1024 * 1024];
        array1 = null;

这行代码直接分配了一个4MB的大对象,此时这个对象会直接进入老年代,接着array1不再引用这个对象。

如下图所示:

接着看如下代码:

        byte[] array2 = new byte[2 * 1024 * 1024];
        byte[] array3 = new byte[2 * 1024 * 1024];
        byte[] array4 = new byte[2 * 1024 * 1024];
        byte[] array5 = new byte[128 * 1024];

 连续分配了4个数组,其中3个是2MB的数组,1个是128KB的数组,如下图所示,全部会进入Eden区域中。

接着会执行如下代码:byte[] array6 = new byte[2 * 1024 * 1024];。

因为Eden 区已经放不下了,所以此时会触发一次Young GC。对应的GC日志如下:

ParNew (promotion failed): 7256K->7953K(9216K), 0.0028080 secs

 这行日志显示,Eden区原来有700多KB的对象,但是回收之后发现一个都回收不掉,因为都被变量引用了。

所以,正常来说一定会直接把这些对象放入到老年代里去,但是此时老年代已经有一个4MB的数组了,不能再放下3个2MB的数组和1个128KB的数组。

 接着有如下GC日志:

[CMS: 8194K->6805K(10240K), 0.0035630 secs] 11352K->6805K(19456K), [Metaspace: 2644K->2644K(1056768K)], 0.0068409 secs]

上述日志,说明执行了CMS垃圾回收器的Full GC。也就是对老年代进行Old GC,同时一般会跟一次Young GC关联,并触发一次元数据区(永久代)的GC。

在CMS Full GC之前,就已经触发过Young GC了,此时可以看到Young GC已经有了,接着就是执行针对老年代的Old GC,如下GC日志:

CMS: 8194K->6805K(10240K), 0.0035630 secs

这里看到老年代从8MB左右的对象占用,变成了6MB多的对象占用。这个过程是,在Young GC之后,先把2个2MB的数组放入了老年代,如下图:

此时要继续放1个2MB的数组和1个128KB的数组到老年代,一定会放不下,所以就会触发CMS的Full GC。从而回收掉其中的一个4MB的数组,因为它没有引用了。

 接着放入一个2MB的数组和1个128KB的数组,如下图所示:

再结合CMS的垃圾回收日志:  CMS: 8194K->6805K(10240K), 0.0035630 secs ,它是从回收前的8MB变成了6MB。

最后在CMS Full GC执行完毕之后,年轻代的对象都进入了老年代,此时最后一行代码要在年轻代分配2MB的数组就可以成功了。

4.深入解析

(1)4MB的大对象Array1给分配内存空间时直接进入老年代,此时不会有GC。因为老年代10M可连续的空闲空间;

(2)当年轻代Eden区域分配完3个2M和1个128K对象后,当分配第四个2M对象时。此时Eden空间不够导致分配失败,触发Minor GC,此时新生代存活的对象6M+128K大于老年代的可用连续空间,但是老年代可用连续空间大于历代新生代进入老年代对象的平均大小0,所以分配担当成功,不需要触发Full GC执行Minor GC;

(3)执行Minor GC年轻代6M+128K对象都存活,但是S0只有1M空间导致存活对象进入老年代;

(4)年轻代先将活着的两个2M对象和128K的对象放入老年代,此时老年代8M+128K,当分配最后一个2M对象触发Full GC,因为可用连续空间小于了2M。此时老年代其中4M大对象可回收2个2M对象和1个128K对象不能回收,Full GC回收完4M对象后再将新生代最后活着的2M对象加入到老年代,所以Minor GC时内存空间是没变的。因为对象都活着,Full GC从8M变成6M。

5.总结

上述案例,当年轻代存活的对象太多放不下老年代了,就会触发CMS的Full  GC。


推荐阅读
  • 使用TabActivity实现Android顶部选项卡功能
    本文介绍如何通过继承TabActivity来创建Android应用中的顶部选项卡。通过简单的步骤,您可以轻松地添加多个选项卡,并实现基本的界面切换功能。 ... [详细]
  • 本文将详细介绍如何使用Java编程语言生成指定数量的不重复随机数,包括具体的实现方法和代码示例。适合初学者和有一定基础的开发者参考。 ... [详细]
  • Go从入门到精通系列视频之go编程语言密码学哈希算法(二) ... [详细]
  • protobuf 使用心得:解析与编码陷阱
    本文记录了一次在广告系统中使用protobuf进行数据交换时遇到的问题及其解决过程。通过这次经历,我们将探讨protobuf的特性和编码机制,帮助开发者避免类似的陷阱。 ... [详细]
  • PHP面试题精选及答案解析
    本文精选了新浪PHP笔试题及最新的PHP面试题,并提供了详细的答案解析,帮助求职者更好地准备PHP相关的面试。 ... [详细]
  • JUC并发编程——线程的基本方法使用
    目录一、线程名称设置和获取二、线程的sleep()三、线程的interrupt四、join()五、yield()六、wait(),notify(),notifyAll( ... [详细]
  • 本文详细介绍了Oracle 11g中的创建表空间的方法,以及如何设置客户端和服务端的基本配置,包括用户管理、环境变量配置等。 ... [详细]
  • 近期尝试从www.hub.sciverse.com网站通过编程手段获取数据时遇到问题,起初尝试使用WebBrowser控件进行数据抓取,但发现使用GET方法翻页时,返回的HTML代码始终相同。进一步探究后了解到,该网站的数据是通过Ajax异步加载的,可通过HTTP查看详细的JSON响应。 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 本文探讨了在Windows系统中运行Apache服务器时频繁出现崩溃的问题,并提供了多种可能的解决方案和建议。错误日志显示多个子进程因达到最大请求限制而退出。 ... [详细]
  • 深入解析JVM内存模型与分配机制
    本文详细探讨了JVM内存结构的主要组成部分,包括Java虚拟机栈、Java堆、方法区等,并深入分析了HotSpot虚拟机的分代收集策略及其对不同内存区域的管理方式。 ... [详细]
  • 本文探讨了在使用JavaMail发送电子邮件时,抄送功能未能正常工作的问题,并提供了详细的代码示例和解决方法。 ... [详细]
  • 本文详细介绍了Android系统的四层架构,包括应用程序层、应用框架层、库与Android运行时层以及Linux内核层,并提供了如何关闭Android系统的步骤。 ... [详细]
author-avatar
品花人生1
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有