JVM(四)

什么时候触发新生代和老年代的混合垃圾回收

G1有一个参数-XX:InitiatingHeapOccupancyPercent,他的默认是45%,他的含义就是老年代到了45%的时候,就会进行混合回收,比如有2048个region,其中老年代占据了有1000个region,就会混合回收.

G1垃圾回收的具体过程

初始化标记

初始化标记先停止新运行,然后对线程内存中的局部变量代表的GC Roots,以及方法区中的静态变量代表的GC Roots,进行扫描,标记他们的直接引用

并发标记

并发标记系统正常运行,并发标记就是从GC Roots开始最终所有存活对象,由于系统正常运行,此时会记录修改的对象

最终标记

最终标记,系统就会停止运行,根据并发标记阶段记录的那些向修改,最终标记一下那些对象存活,那些垃圾对象

混合回收

最后一个阶段,计算老年代中每个region中存活的对象数量,存活对象占比,还有执行垃圾回收预期性能和效率,此时系统停止运行,全力进行垃圾回收,此时会选择部分region进行回收,因为必须让垃圾回收停顿时间在控制范围内,

例如,老年代有1000个region都满了,预期目标就是200ms的停顿时间,通过计算最大能回收800个region,这样把停顿时间控制在范围内,

说明一点就是老年代达到45%(-XX:InitiatingHeapOccupancyPercent进行设置,默认是45%)的时候,触发的是混合回收,就是说回收老年代和年轻代,以及大对象,

G1垃圾回收重要参数

我们知道G1垃圾回收有几个阶段,最后一个阶段就是混合回收,其实停止所有程序运行,然后在进行全力回收,但是我要注意的是,这个回收可能要反复好几次,反复几次是有-XX:G1MixedGCCountTarget参数控制,默认值8,就会每次回收会反复回收8次,比如我们预期要会搜160个region,因此每次会回收20个region,反复8次就可以回收160region,这样所得好处就是,是系统有间隙执行系统,不会一直停顿,

另外一个参数-XX:G1HeapWastePercent,默认是5%,由于我们的G1回收是基于复制算法进行的,因此他会把存活的而对象复制到另外一个region,然后一次性清理有垃圾的region,而这个参数的作用就是混合回收的空闲region达到堆内存的5%的时候,就会停止混合回收,意味回收就结束了,

另外一个参数“-XX:G1MixedGCLiveThresholdPercent 默认是85%,作用就是要回收的region存活的对象必须低于85%才会被回收,不然存活对象大于85%,回收他成本很高

回收失败的情况

当然我们知道,复制算法,是要把存活的对象复制到另外一个region,但是如果没有空闲的region可以存放存活的对象,就会触发失败,一旦失败,就会停止系统程序,然后采用单线程进行标记,清理,压缩整理,空闲一批region,切记这个过程很慢

G1垃圾回收中如何触发新生代GC

背景是堆内存是4G,一共2048个region,每个region是2M,其中新生代开始占5%,也就是100region,新生代200M,假设系统每秒产生3M,则一分钟新生代Eden几乎就满了,这里我就想起以前我们记得是当Eden满的时候触发GC,

但是G1,不是这样的,因为如果此时回收这200M内存消耗几十毫秒,而我们记得参数-XX:MaxGCPauseMills=200ms,和我们预期的相差太远

而且这样回收回到每分钟就会发生一个新生代GC,频繁的发生GC,是没有这个必要的,因此不如在此时给新生代再分配一些region,然后新生代继续分配对象,最后G1发现回收300m内存需要消耗200ms,那这个时候触发一次新生代GC,是最好的,这个我们要明白G1是很灵活的,他会根据你设定的gc停顿时间给你的新生代不停的分配region,到的一定程度,就会触发新生代GC,保证在预期的时间范围内。大致思想就是上面这些,但是具体还要根据实际情况才知道.

mixed GC如何优化

mixed GC是当老年代占堆内存超过45%的时候就会触发,这mixed gc优化的核心不是参数的优化,是如何让新生代不会进入老年代,所以最重要的还是我们之前说的参数-XX:MaxGCPauseMills参数,如果设置大了,就会新生代达到60%才会触发新生代GC,且存活的对象就会很多,而此时Suvivor放不下对象,就会进入老年代,所以要保证-xx:MaxGCPauseMills参数既要保证新生代不要频繁的gc,还要保证存活的对象有多少,避免存活对象太多进入老年代,频繁发生Mied GC

运行的系统,怎么会卡顿呢

我们的系统正常运行,对象不断的产生,当新生代Eden块要满的时候,就会发生垃圾回收,此时就会把存活的对象放到S1,那些是存活的对象就是GC Roots引用的对象,如类的静态变量和实例变量,被这些对象引用,就是存活的对象,

更重要的是系统此时是对外是停止运行,这个就是Stop the World,就会导致系统卡顿的问题,

新生代gc对系统的卡顿的影响

一般我们新生代进行GC,如果内存足够,几个小时进行新生代GC,高峰期最多也就几分钟一次新生代GC,通常新生代复制算法效率很高,因此一般情况下,只有少数的对象,然后进行回收对系统影响很小

但是如果你的机器是一个32核64G的机器,分给堆内存大概就有几十GC,Eden可能有30-40的内存,

正好的你使用了kafak,elasticserch之类的大数据系统,部署在大内存机器中,每秒几万的请求,就可能导致几十G内存发生频发内存发生,假设1分钟会塞满一次,每次GC,都会消耗几百毫秒,甚至1秒,就会导致你的系统卡顿,这个频繁的卡顿,对用户影响极大

如何解决大内存新生代GC过慢的问题

其实遇到大内存的机器GC,我们肯定就想到了G1垃圾收集器,G1就是为了大内存机器垃圾回收慢的问题场景提供的,

G1预估系统停顿的时候,让垃圾在合理的时间内进行回收,完美的解决了停顿时间过程的问题,同时我们要知道频繁老年代GC的问题

前面我们讲过新生代gc问题不大,问题是频繁的老年代GC问题,我们也讲过进入老年代的几个条件就是,年龄多大,新生代的survivor存活对象太多,无法进入Survivor中,进入老年代,还有就是动态年龄判定规则,suvivor区域几个年龄对象加起来超过Survivor的50%

我们要知道老年代的GC是非常慢的,比如新生代一次GC消耗200ms,对用户影响不大,但是老年代耗费2s,就会导致页面卡顿2s,影响很大的,根本解决问题就是尽可能不让对象进入老年代.

本文分享自微信公众号 - 洁癖是一只狗(rookie-dog),作者:洁癖汪

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-08-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JVM 《四 JVM 中的String》

    String 这样的量,在我们的认知中是比较特别的。 其中String 是个对象,然后String也可以是个普通的字面量。在每代JDK中对String 的处理...

    邹志全
  • jvm系列(四):jvm调优-命令篇

    运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole、大名鼎鼎的VisualVM...

    纯洁的微笑
  • 深入理解JVM(四)——对象内存的分配策略

    Java所承诺的自动内存管理主要是针对对象内存的回收和对象内存的分配。 在Java虚拟机的五块内存空间中,程序计数器、Java虚拟机栈、本地方法栈内存的分配和回...

    大闲人柴毛毛
  • JVM(四)垃圾回收的实现算法和执行细节

    上一篇我们讲了垃圾标记的一些实现细节和经典算法,而本文将系统的讲解一下垃圾回收的经典算法,和Hotspot虚拟机执行垃圾回收的一些实现细节,比如安全点和安全区域...

    Java中文社群-磊哥
  • 四、JVM分代收集理论

    当前商业虚拟机的垃圾收集器,大多数都遵循了“分代收集”(Generational Collection)的理论进行设计,所谓分代,就是将Java堆划分出不同的区...

    大数据程序猿
  • JVM技术总结之四——JVM内存结构

    每个线程由多个栈帧构成,每个栈帧包含线程中该方法的处理信息。栈帧由四部分组成:局部变量表、操作数栈、动态链接、方法返回地址。

    剑影啸清寒
  • JVM 学习笔记(四)

      在之前的文章中,我们主要体现了当堆内存设置的比较小的情况下,比如:-Xmx20M -Xms20M,在项目运行的过程中,不断往内存中去添加对象,

    会说话的丶猫
  • 用Java实现JVM第四章《运行时数据区》

    案例介绍 本案例初步实现运行时数据区里;线程、Java虚拟机栈、帧、操作数栈、局部变量表。

    小傅哥
  • 用Java实现JVM第四章《运行时数据区》

    小傅哥
  • JVM系列四(内存分配策略).

    前面的文章介绍了对象的创建过程,其中第三步 —— 分配内存,只是简单的介绍了分配的方式 —— 指针碰撞、空闲列表,其实内存在堆上分配还大有文章嘞。

    JMCui
  • jvm源码分析(四)ThreadPoolExecutor

    它是把已创建的线程放入“池”中,当有任务来临,就可以重用已有的线程,无需等待创建的过程,可以有效提高程序的响应速度。

    用户6203048
  • 简述JVM基础(四):类结构文件

    Class文件是以8个字节为单位的二进制流,紧凑排列,中间没有空隙;如果想查看一个Class文件除了通过winHex编译器看到字节码,也可以通过javap -v...

    open
  • Java虚拟机(四):JVM类加载机制

    类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类...

    朝雨忆轻尘
  • 搜狐面试官:说说你理解的JVM中四种引用类型!

    强引用是默认支持,当内存不足的时候,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会回收对象。

    Java程序猿
  • 基于JavaAgent的全链路监控四《JVM内存与GC信息》

    案例简述 除了监控java方法的执行耗时,我们还需要获取应用实例的jvm内存与gc信息,以实时把控我们的服务器性能是否在安全范围。监控jvm内存与gc信息是非常...

    小傅哥
  • 腾讯Java岗位(技术四面)-MySQL、jvm、spring、redis

    获取往期以上更多最新面试题资料,直接转发一下这篇文章+关注公众号【Java烂猪皮】关注后回复【666】即可获取哦~

    烂猪皮
  • GC和垃圾回收器其四:一次JVM调参之旅

    HotspotVM垃圾回收采用分代回收算法,分代回收基于这样一个事实:对象生命周期不同,针对不同生命周期的对象可以采取不同的回收策略。

    春哥大魔王
  • 【JVM进阶之路】四:直面内存溢出和内存泄漏

    在JVM的几个内存区域中,除了程序计数器外,其他几个运行时区域都有发生内存溢出(OOM)异常的可能。

    三分恶
  • JVM学习系列学习四

    本文是《JVM学习系列》中的第三篇文章。如果想系统的学习,建议从本教程第一篇开始看。

    凯哥Java

扫码关注云+社区

领取腾讯云代金券