JVM实战(18)——模拟Full GC

这篇具有很好参考价值的文章主要介绍了JVM实战(18)——模拟Full GC。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析

阶段4、深入jdk其余源码解析

阶段5、深入jvm源码解析

一、简介

上一章,我们已经进行了一次对象晋升的模拟,本章我们将继续结合代码示例做实验,来看看老年代的GC是如何触发的。

1.1 JVM内存参数

我们的示例程序基于JDK1.8,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

上述给新生代分配了10MB空间,老年代也是10MB,参数注意一点:

  • -XX:PretenureSizeThreshold=3145728:超过3MB的大对象直接进入老年代

JVM实战(18)——模拟Full GC,jvm专题,jvm

二、示例程序

2.1 程序源码

示例程序代码如下:

    public class Demo1 {
        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.2 JVM内存模型

我们根据上述代码来分析下内存中的对象分配。首先创建4MB的数组对象,由于超过大对象阈值3MB,所以直接进入老年代:

JVM实战(18)——模拟Full GC,jvm专题,jvm

接着array1失去引用,然后在Eden区分配3个2MB数组和1个128KB数组:

JVM实战(18)——模拟Full GC,jvm专题,jvm

然后,执行代码byte[] array6 = new byte[2 * 1024 * 1024],希望在Eden区继续创建一个2MB的数组。显然,Eden区的空间不足了,此时即将触发Young GC。

2.3 程序执行

我们执行程序,得到以下GC日志:

    0.260: [GC (Allocation Failure) 0.261: [ParNew (promotion failed): 8142K->8797K(9216K), 0.0035404 secs]0.264: [CMS: 8194K->6772K(10240K), 0.0064863 secs] 12238K->6772K(19456K), [Metaspace: 3227K->3227K(1056768K)], 0.0103195 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
    0.272: [GC (CMS Initial Mark) [1 CMS-initial-mark: 6772K(10240K)] 9112K(19456K), 0.0004078 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    0.273: [CMS-concurrent-mark-start]
    0.274: [CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    0.274: [CMS-concurrent-preclean-start]
    0.274: [CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
    0.274: [CMS-concurrent-abortable-preclean-start]
    Heap
     par new generation   total 9216K, used 2422K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
      eden space 8192K,  29% used [0x00000000fec00000, 0x00000000fee5d898, 0x00000000ff400000)
      from space 1024K,   0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
      to   space 1024K,   0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
     concurrent mark-sweep generation total 10240K, used 6772K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
     Metaspace       used 3233K, capacity 4496K, committed 4864K, reserved 1056768K
      class space    used 350K, capacity 388K, committed 512K, reserved 1048576K

三、日志分析

我们先来看下日志中的下面这行,这是本轮GC情况的概要说明:

    0.260: [GC (Allocation Failure) 0.261: [ParNew (promotion failed): 8142K->8797K(9216K), 0.0035404 secs]0.264: [CMS: 8194K->6772K(10240K), 0.0064863 secs] 12238K->6772K(19456K), [Metaspace: 3227K->3227K(1056768K)], 0.0103195 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

ParNew (promotion failed): 8142K->8797K(9216K), 0.0035404 secs: :这行表明ParNew首先进行了一次Young GC,但是发现Eden区内的对象全部被引用着,一个都回收不掉。于是会尝试将存活对象转移到Survivor,是Survivor空间不足,所以又会尝试转移到老年代,但是老年代可用空间也只有6MB,容纳不了3个2MB和1个128KB数组,所以就会触发下面的Full GC。

[CMS: 8194K->6772K(10240K), 0.0064863 secs] 12238K->6772K(19456K), [Metaspace: 3227K->3227K(1056768K)], 0.0103195 secs: 从这里可以看到,CMS垃圾回收器执行了Full GC,Full GC会对老年代进行Old GC,并是和上面的Young GC关联的,同时还会对元数据区(永久代)进行回收。

因为,老年代虽然容纳不了全部3个2MB数组和1个128KB数组,但是可以容纳2个2MB数组,所以会先将这两个2MB数组对象转移到老年代:

JVM实战(18)——模拟Full GC,jvm专题,jvm

然后,发现剩下的一个2MB数组和128KB数组实在放不下了,就会进行一次Old GC([CMS: 8194K->6772K(10240K), 0.0064863 secs] ),可以看到老年代空间最终变成了6772KB。

因为CMS进行Old GC时先对老年代清理,回收掉没有引用的那个4MB数组,然后将新生代中的2MB数组和128KB数组转移到老年代:

JVM实战(18)——模拟Full GC,jvm专题,jvm

最后,Full GC完毕后,byte[] array6 = new byte[2 * 1024 * 1024]这行代码对应的2MB数组被成功分配到Eden区:

JVM实战(18)——模拟Full GC,jvm专题,jvm

四、总结

本章通过GC日志分析了一个触发老年代GC的案例,即新生代存活对象太多,放不进Survivor区,同时也放不进老年代,此时就会触发CMS的Full GC。
当然,触发老年代GC的另一种情况就是:当老年代内存占用达到一定的比例,通过 -XX:CMSInitiatingOccupancyFaction参数可以设置这个比例,JDK1.6中默认是92%。文章来源地址https://www.toymoban.com/news/detail-801470.html

到了这里,关于JVM实战(18)——模拟Full GC的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM实战篇:GC调优

    目录 一.GC调优的核心指标 1.1吞吐量(Throughput) 1.2延迟(Latency) 1.3内存使用量 二.GC调优的方法 2.1监控工具 Jstat工具 VisualVm插件 Prometheus + Grafana 2.2诊断原因 GC日志 GC Viewer GCeasy 2.3常见的GC模式 正常情况 缓存对象过多 内存泄漏 持续的FULL GC 元空间不足导致的FULL GC 三.修复G

    2024年01月23日
    浏览(42)
  • JVM实战(14)——Young GC调优

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月16日
    浏览(36)
  • JVM实战(17)——模拟对象晋升

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月19日
    浏览(36)
  • JVM实战(30)——模拟堆内存溢出

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月25日
    浏览(51)
  • JVM实战(28)——模拟Metaspace内存溢出

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月18日
    浏览(41)
  • 【JVM】JVM垃圾回收GC相关参数说明

    -XX:+PrintCommandLineFlags : 输出JVM启动参数 -XX:+UseSerialGC :在新生代和老年代使用串行收集器 -XX:SurvivorRatio :设置eden区大小和survivior区大小的比例 -XX:NewRatio :新生代和老年代的比 -XX:+UseParNewGC :在新生代使用并行收集器 -XX:+UseParallelGC :新生代使用并行回收收集器 -XX:+UseParallelO

    2024年02月04日
    浏览(47)
  • JVM 配置GC日志

    开启GC日志 多种方法都能开启GC的日志功能,其中包括:使用-verbose:gc或-XX:+PrintGC这两个标志中的任意一个能创建基本的GC日志 (这两个日志标志实际上互为别名,默认情况下的GC日志功能是关闭的) 使用-XX:+PrintGCDetails标志会创建更详细的GC日志 推荐使用-XX:+PrintGCDetails标志(

    2024年02月15日
    浏览(47)
  • 【JVM】垃圾回收 GC

    垃圾回收(Garbage Collection,GC)是由 Java 虚拟机(JVM)垃圾回收器提供的一种对内存回收的一种机制,它一般会在内存空闲或者内存占用过高的时候对那些没有任何引用的对象不定时地进行回收。以避免内存溢出和崩溃的问题。JVM的垃圾回收算法包括引用类型、引用计数器法

    2024年01月16日
    浏览(49)
  • JVM GC 区别

    串行收集器 : Serial , Serial Old 只有一个垃圾回收线程执行,用户线程会暂停 适用 : 内存较小的嵌入式设备 并行收集器 [吞吐量优先] : Parallel Scanvenge、Parallel Old 多条垃圾收集线程并行工作,但用户线程会是等待状态 适用 : 科学计算、后台处理 并发收集器 [停顿时间优先] : CM

    2024年02月11日
    浏览(59)
  • JVM GC配置指南

    本文旨在简明扼要说明各回收器调优参数,如有疏漏欢迎指正。 1、JDK版本 以下所有优化全部基于JDK8版本,强烈建议低版本升级到JDK8,并尽可能使用update_191以后版本。 2、如何选择垃圾回收器 响应优先应用:面向C端对响应时间敏感的应用,堆内存8G以上建议选择G1,堆内存

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包