JVM之垃圾回收器

11 篇文章 1 订阅
3 篇文章 0 订阅

堆中逻辑分代是「给内存做一些概念上的区分」,物理分代是真正的物理内存。

「具体划分」

新生代(young)和老年代(old/tenured)。

「新生代」:刚new出来的那些对象:默认比例1

「老年代」:垃圾回收了很多次都没有把它回收掉的老对象:默认比例3

新生代又分为:

  • 「eden」 默认比例是8。新new出来的对象放在eden区。

  • 「survivor 0」(s1) 默认比例是1。垃圾回收一次之后跑到这个区域,该区域存放的对象不同,采取的垃圾回收算法也不同。

  • 「survivor 1」(s2) 默认比例是1。

新生代存活的对象较少,使用的垃圾回收算法是拷贝算法(Copying)。

老年代活着的对象较多,垃圾回收算法适用标记压缩(Mark Compact)或者标记清除(Mark Sweep)。

「几个GC的概念」

  • MinorGC/YGC 新生代空间耗尽时触发的垃圾回收。

  • MajorGC/FullGC 在老年代无法继续分配空间时触发,新生代、老年代同时进行垃圾回收。

 2. 一个对象的生命历程-从出生到消亡

一个对象被new出来之后,首先尝试进行栈上分配,栈上如果分配不下才会进入eden区(虚拟机提供了一个XX:MaxTenuringThreshold参数,令大于这个设置值的对象直接在老年代分配,这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制);

eden区经过一次垃圾回收之后进入一个survivor区-s1区;

survivor区(s1)经过一次垃圾回收之后又进入另一个survivor区-s2区,同时eden区的某些对象也会跟着进入s2;

当对象年龄到某一个值后,会进入到old区。这个值可以通过参数:

-XX:MaxTenuringThreshold

进行配置。

动态对象年龄判定

为了能更好地适应不同程度的内存状况,虚拟机并不是永远地要求对象的年龄必须达到才能晋升老年代,如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于改年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄

下面这个图能够帮助我们了解JVM中内存分区的概念。

当进行垃圾回收处理时, 会进入「STW - Stop The World」,就是所有的线程都会停止,等待回收结束后才会继续执行;所以这样会导致项目的卡顿;为了避免这个问题,所以我们需要减少进入垃圾回收处理阶段;有时候需要调大核心进程数,避免堆中内存满的情况出现;或者是调大MaxTenuringThreshold的值,减少内存满的情况出现

5. 常见的垃圾回收器

在 JVM 中,具体实现有 SerialParNewParallel ScavengeCMSSerial Old(MSC)Parallel OldG1 等

如果当 垃圾回收器 进行垃圾清理时,必须 暂停 其他所有的 工作线程,直到它完全收集结束。我们称这种需要暂停工作线程才能进行清理的策略为 Stop-the-World 

  • 新生代回收器:Serial、ParNew、Parallel Scavenge

  • 老年代回收器:Serial Old、Parallel Old、CMS

  • 整堆回收器:G1、ZGC(最有可能转正)、Shenandoah

现在1.8JDK版本中,最常用到的垃圾回收器是(一般是PS+PO结合)

5.1 「Serial」

采用的是复制算法,当Serial工作的时候,所有正在工作的线程全部停止。

线程停止有一个「safe point」(安全点),需要找到一个安全点上进行线程停止,该垃圾回收器停顿时间较长(「STW - Stop The World」),现在用的较少。

5.2 「ParNew」

Parallel NEW的意思,就是Parallel Scavenge的新版本。它就是在PS的基础上做了一些增强以便它能和「CMS」配合使用,CMS在某一个特定阶段的时候会和ParNew同时运行。

ParNew工作的时候其余线程不能工作,必须等GC结束才行。

它工作时也STW,采用的是Copying算法,多线程执行。

 

 5.3 「Parallel Scavenge」

新生代的收集器,同样用的是复制算法,也是并行多线程收集。与ParNew最大的不同,它关注的是垃圾回收的吞吐量。

这里的吞吐量指的是 总时间与垃圾回收时间的比例。这个比例越高,证明垃圾回收占整个程序运行的比例越小。

Parallel Scavenge收集器提供两个参数控制垃圾回收的执行:

  • -XX:MaxGCPauseMillis,最大垃圾回收停顿时间。这个参数的原理是空间换时间,收集器会控制新生代的区域大小,从而尽可能保证回收少于这个最大停顿时间。简单的说就是回收的区域越小,那么耗费的时间也越小。
    所以这个参数并不是设置得越小越好。设太小的话,新生代空间会太小,从而更频繁的触发GC。
  • -XX:GCTimeRatio,垃圾回收时间与总时间占比。这个是吞吐量的倒数,原理和MaxGCPauseMillis相同。

因为Parallel Scavenge收集器关注的是吞吐量,所以当设置好以上参数的时候,同时不想设置各个区域大小(新生代,老年代等)。可以开启**-XX:UseAdaptiveSizePolicy**参数,让JVM监控收集的性能,动态调整这些区域大小参数。

5.4 「Serial Old」

用于老年代,也是「STW」,采用的是标记压缩算法(标记-整理(Mark-Compact)),单线程。

因为老年代里面对象的存活率高,如果依旧是用复制算法,需要复制的内容较多,性能较差。并且在极端情况下,当存活为100%时,没有办法用复制算法。所以需要用Mark-Compact,以有效地避免这些问题。

5.5 「Parallel Old」

 用于老年代,STW,多线程执行,采用标记压缩算法(Mark-Compact)。

5.6 「CMS」

前面几种垃圾回收器有一个共性就是STW,就是我垃圾回收器在工作的时候其他人都不许动,得等着,我干完了,你们才能继续工作。

CMS的诞生就是试图解决这个问题。然而不STW了,那么怎么判断一个对象是否是垃圾,就成了关键的关键。CMS本身的问题很多,目前任何JDK版本默认的垃圾回收器都不是CMS

CMS - Concurrent Mark Sweep,并发标记清除。从线程的角度看,CMS进行垃圾回收的时候和工作线程同时进行,但是它依然很慢。

在以往内存较小的时候,速度很快,但现在服务器内存已经很大了,相当于原来在10平米的房间内清理垃圾,现在需要在100平米甚至更大的空间内清理垃圾,即使使用多线程来清理也需要很长的时间 

1、初始标记(CMS initial mark)

初始标记 仅仅是标记 GC Roots直接关联 的对象。这个阶段 速度很快需要 Stop the World

2、并发标记(CMS concurrent mark)

并发标记 进行的是 GC Tracing,从 GC Roots 开始对堆进行 可达性分析,找出 存活对象

3、重新标记(CMS remark)

重新标记 阶段为了 修正 并发期间由于 用户进行运作 导致的 标记变动 的那一部分对象的 标记记录。这个阶段的 停顿时间 一般会比 初始标记阶段 稍长一些,但远比 并发标记 的时间短,也需要 Stop The World

4、并发清除(CMS concurrent sweep)

并发清除 阶段会清除垃圾对象。其他用户线程仍可以工作,不需要停顿。

初始标记CMS initial mark)和 重新标记CMS remark)会导致 用户线程 卡顿,Stop the World 现象发生。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值