GC(JAVA垃圾回收)

目录

标记-复制

标记-清除-整理

GC Root对象

安全点检测

串行GC

并行GC

CMS GC

G1 GC

ZGC

JDK使用的默认GC

GC算法的选择


标记-复制

        年轻代分为,eden,s0,s1三个区;

        新new出来的对象,放在eden区,eden区满后,做young gc,把eden区中的存活对象,复制

到s0区,然后清空eden区;

        下一次young gc时,把eden区和s0区中的存活对象,一起复制到s1区,然后清空eden区和s0

区;之后按着上述规则循环操作;

        当年轻代的存活对象,经过默认15次(可通过参数修改)的young gc之后,还存活着,就会

晋升到老年代;

标记-清除-整理

        遍历并标记所有的可达对象,清除不可达对象所占用的内存,清除垃圾之后的内存空间不连

续,做碎片整理,让内存空间连续起来;

        标记存活对象的过程,是通过遍历GC Root对象引用的对象来实现的;

GC Root对象

        标记可达对象时,是从GC Root对象出发,然后遍历所有可以达到的对象;GC Root对象:

        1,当前正在执行的方法里的局部变量和输入参数相关的对象;

        2,活动线程相关的对象;

        3,所有类的静态字段相关的对象;

        4,Java本地接口引用相关的对象;

安全点检测

        GC回收内存时,会触发全线暂停STW;

        JVM中的STW(Stop-the-world) 是通过安全点(safepoint)机制来实现的。当虚拟机收到

Stop-the-world请求,它便会等待所有的线程都到达安全点,才允许请求STW的线程进行独占的工

作。

        安全点的初始目的并不是让其他线程停下,而是找到一个稳定的执行状态。在这个执行状态

下,JVM的堆栈不会发生变化。垃圾回收器便能够“安全”地执行可达性分析。

        对于解释执行来说,字节码与字节码之间皆可作为安全点。当有安全点请求时,执行一条字

节码便进行一次安全点检测。

        执行即时编译器生成的机器码则比较复杂。由于这些代码直接运行在底层硬件之上,不受

JVM掌控,因此在生成机器码时,即时编译器需要插入安全点检测,以避免机器码长时间没有安全

点检测的情况。

串行GC

        启动参数:-XX:+UseSerialGC

        特点

        年轻代使用标记-复制算法,老年代使用标记-清除-整理算法;

        两者都是单线程的垃圾收集器,不能进行并行处理,都会触发全线暂停(STW),停止所有

的应用线程。

        串行GC不能充分利用多核 CPU。不管有多少 CPU 内核,JVM 在垃圾收集时都只能使用单个

核心。

        适用场景:该选项只适合几百 MB 堆内存的 JVM,而且是单核 CPU 时比较有用。

并行GC

        启动参数:-XX:+UseParallelGC

        特点

        年轻代使用标记-复制算法,老年代使用标记-清除-整理算法;

        年轻代和老年代的垃圾回收都会触发 STW 事件;

        GC时,多线程回收垃圾,线程数默认位CPU核数,可通过参数调整;

        GC 期间,所有CPU内核都在并行清理垃圾,所以总暂停时间更短;

        适用场景:适用于多核服务器,适用于对吞吐量有要求的场景,对系统资源的有效使用,能

达到更高的吞吐量:

CMS GC

        启动参数:-XX:+UseConcMarkSweepGC

        特点

        年轻代使用标记-复制算法,触发STW;

        老年代采用标记-清除算法,老年代做垃圾回收时,和业务线程并发执行,从而减少老年代GC

时的STW时间:

        1,不对老年代进行整理,而是使用空闲列表(free-lists)来管理内存空间的回收。

        2,在 标记-清除阶段的大部分工作和应用线程一起并发执行。

        默认情况下做标记-清除算法的并发线程数等于 CPU 核心数的 1/4。

        老年代GC的步骤

        1,初始标记,为了标记的准确,短暂的STW;

        2,并发标记,GC线程和业务线程并行,并发标记,会有误差;

        3,并发预清理,GC线程和业务线程并行,处理步骤2中的标记误差;

        4,最终标记,为了标记的准确,短暂的STW;

        5,并发清除

        6,并发重置

        适用场景:多核 CPU,对GC停顿导致的系统延迟要求较高;

G1 GC

        启动参数:-XX:+UseG1GC -XX:MaxGCPauseMillis=50

        MaxGCPauseMillis=50 指定单次GC导致的STW尽量控制在50ms左右;

        特点

        堆不再分成年轻代和老年代,而是划分为多个可以存放对象的小块堆区域;

        每个小块,动态的被指定为:Eden 区,Survivor区,Old 区;

        Eden 区和 Survivor 区合起来就是年轻代,Old 区拼在一起那就是老年代。

        G1 不必每次都去收集整个堆空间,每次只处理一部分内存块。

        收集原则是:垃圾最多的小块会被优先收集。每次收集的量,控制在MaxGCPauseMillis参数

指定的时间能收集完成;

        重要参数

        -XX:G1NewSizePercent:初始年轻代占整个 Java Heap 的大小,默认值为 5%;

        -XX:G1MaxNewSizePercent:最大年轻代占整个 Java Heap 的大小,默认值为 60%;

        -XX:G1HeapRegionSize:设置每个内存块的大小,单位 MB,需要为 1、2、4、8、16、

32 中的某个值,默认是堆内存的1/2000;

        -XX:ConcGCThreads:与 业务线程一起执行的 GC 线程数量,默认是 Java 线程的 1/4;

        -XX:+InitiatingHeapOccupancyPercent:触发老年代回收的内存使用阈值,默认为堆大小的

45%;

        -XX:G1HeapWastePercent:停止GC回收的内存使用阈值,默认是堆大小的 5%;

        -XX:MaxGCPauseMills:预期G1 GC每次执行操作的暂停时间,单位是毫秒,G1 GC会尽

量(不是一定)保证控制在这个范围内;

        G1 GC的注意事项

        某些情况下G1会退化使用串行收集器来完成垃圾的清理工作,仅仅使用单线程来完成 GC 工

作,GC 暂停时间将大幅增加;

        1,晋升失败

        没有足够的内存供存活对象或晋升对象使用,由此触发了 Full GC(to-space exhausted/to-

space overflow)。

        解决办法:

        a) 增加 –XX:G1ReservePercent 选项的值(并相应增加总的堆大小)增加预留内存量。

        b) 通过减少 –XX:InitiatingHeapOccupancyPercent 提前启动标记周期。

        c) 也可以通过增加 –XX:ConcGCThreads 选项的值来增加并行标记线程的数目。

        2,巨型对象分配失败

        当巨型对象找不到合适的空间进行分配时,就会启动 Full GC,来释放空间。

        解决办法:增加内存或者增大 -XX:G1HeapRegionSize

        适用场景

        内存比较大,且希望GC时间,整体可控;

ZGC

        启动参数:-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xmx16g

        特点

        GC 最大停顿时间不超过 10ms;

        堆内存支持范围广,小至几百 MB 的堆空间,大至 4TB 的超大堆内存(JDK13 升至 16TB)

        与 G1 相比,应用吞吐量下降不超过 15%

        当前只支持 Linux/x64 位平台,JDK15 后支持 MacOS 和Windows 系统;

JDK使用的默认GC

        JDK6,JDK7,JDK8 默认使用并行GC;

        JDK9以及以上上默认使用并行G1 GC;

GC算法的选择

        选择正确的 GC 算法,唯一可行的方式就是去尝试,一般性的指导原则:

        1,如果系统考虑吞吐优先,CPU 资源都用来最大程度处理业务,用 并行 GC;

        2,如果系统考虑低延迟有限,每次 GC 时间尽量短,用 CMS GC;

        3,如果系统内存堆较大,同时希望整体来看平均 GC 时间可控,使用 G1 GC。

        从内存大小的角度考量:

        1,一般 4G 以上,算是比较大,用 G1 的性价比较高。

        2,一般超过 8G,比如 16G-64G 内存,非常推荐使用 G1 GC。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值