垃圾收集算法与垃圾收集器

垃圾收集算法

标记-清除算法

首先标记所有需要回收的对象,在标记完成后统一回收所有被标记的对象(标记过程上一篇说过了)。

缺点:

  • 效率问题,效率不高;
  • 空间问题,标记清除后产生大量不连续的内存碎片,以后运行过程中分配较大对象时,无法找到足够的连续空间导致提前触发另一次回收。

执行过程:
在这里插入图片描述

复制算法

将内存根据容量分为大小相等的两份,首先使用其中一份,当第一份用完时,将第一份中可用对象全部复制到第二份中,并将第一份剩余的对象全部清除。

优缺点:运行高效,将内存压缩为原来的一半,代价高了点。

执行过程
在这里插入图片描述
现在的商业虚拟机都采用这种算法回收新生代,因为新生代对象98%都是朝生夕死的,所以不需要将内存1:1划分,而是将内存分为较大的Eden空间和两块较小的Survivor空间,先使用Eden和其中一个Survivor作为第一份,另一块Survivor作为第二份,执行过程如上所述。

标记-整理算法

将存活对象向一端移动,移动完之后,将末端以后的空间全部清除。

执行过程
在这里插入图片描述

分代收集算法

新生代中一般只有少量对象存活,复制成本低,使用复制算法;老年代存活率高,没有额外的空间分配担保,使用标记-清除或者标记-整理算法。

垃圾收集器

如果说垃圾收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。
收集器如图
如果两个收集器之间又连线,说明可以配合使用
如果两个收集器之间有连线,说明可以配合使用

Serial收集器
  • 复制算法
  • jdk1.3.1之前新生代收集的唯一选择
  • 单线程收集器,进行垃圾收集时,必须暂停其他所有工作线程(Stop The World),直到它收集结束。

Serial/Serial Old收集器的运行过程
在这里插入图片描述

ParNew收集器
  • 复制算法
  • 是Serial的多线程版本,除了多线程垃圾收集,收集算法、回收策略等和Serial完全一样
  • 在Server模式下的虚拟机中首选的新生代收集器,因为新生代收集器中除了Serial目前只有它能与CMS收集器配合工作

ParNew与Serial Old运行过程
在这里插入图片描述

Parallel Scavenge收集器
  • 新生代收集器(吞吐量优先收集器)
  • 复制算法
  • 并行的多线程收集器
    CMS等收集器关注于缩短垃圾收集时用户停顿的时间,Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量:缩短用户停顿时间适合与用户交互较多的程序,提升用户体验,高吞吐量则是可以最高效率的利用cpu时间,尽快完成运算任务,适合后台运算多交互少的任务。
Serial Old
  • 标记-整理算法
  • 是Serial的老年代版本
  • 单线程收集器。
    运行过程图在上边(Serial)
Parallel Old
  • 标记-整理算法
  • 是Paralel Scavenge收集器的老年代版本
  • 多线程收集器
    运行过程
    在这里插入图片描述
CMS收集器
  • 标记清除算法
  • Concurrent Mark Sweep收集器是一种以获取最短回收时间为目标的收集器。
  • 并发收集器,内存回收过程与用户线程一起并发的执行
  • 运行过程:
    1 初始标记
    2 并发标记
    3 重新标记
    4 并发清除
    初始标记、重新标记仍然需要Stop The World。初始标记仅仅是标记GC Roots能直接关联到的对象,速度很快;并发标记阶段是进行GC Roots Tracing的过程;重新标记是为了修正并发标记期间,因用户程序继续运行导致标记产生标动的那一部分对象的标记记录。
    • 优点:并发收集、低停顿
    • 缺点:
      1 CMS收集器对CPU资源非常敏感。
      2 CMS收集器无法处理浮动垃圾(处理期间用户线程产生的新垃圾,产生于标记之后)。
      3 使用标记-清除算法,产生大量的内存碎片

运行过程图
在这里插入图片描述

G1收集器
  • 标记-整理算法
  • 能非常精确的控制停顿,技能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒
    G1将整个java堆划分成多个大小国定的独立区域(Region),并且跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先队列,每次根据允许的收集时间,优先回收垃圾最多的区域(Garbage First名称的由来)

内存分配与回收策略

java自动内存管理归结为自动化解决了两个问题:给对象分配内存以及回收分配给对象的内存。
Serial/Serial Old收集器(ParNew/Serial Old组合也基本一致)下的内存分配和回收策略:
1 对象优先在Eden分配:大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。
2 大对象直接分配进入老年代
大对象指需要大量连续内存空间的对象
虚拟机提供了一个参数,令大对象直接在老年代中分配。这样做的目的是避免在Eden区和两个Survivor区之间发生大量内存拷贝(新生代使用复制算法收集内存);
3 长期存活的对象将进入老年代
虚拟机给对象定义了一个年龄(Age)计数器。如果对象在Eden出生并经过第一次Minor GC仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并将对象年龄设为1.对象在Survivor没熬过一次Minor GC,年龄就增加一岁,当它的年龄增加到一定程度(默认15)时,就会晋升到老年代。
4 动态对象年龄的判定
如果在Survivor空间中相同年龄所有对象大小的综合大于Survivor空间的一般,年龄大于或等于该年龄的对象就可以直接进入老年代。
5 空间分配担保
新生代使用复制算法,只是用一块Survivor空间作为备份,在大量对象在Minor GC后仍然存活时,就需要老年代进行分配担保,把Survivor空间容纳不了的对象放入老年代。

在这里的一些概念
1 并行:指多条垃圾收集线程并行工作,但此时用户线程处于等待状态。
2 并发:指用户线程与垃圾收集线程同时执行(但不一定并行,可能是交替执行),用户程序继续运行,而垃圾收集程序运行于另一个cpu。
3 吞吐量:吞吐量 = 运行用户代码时间 /(运行用户代码时间+垃圾收集时间),如虚拟机总共用了100分钟,其中垃圾收集花了一分钟,那么吞吐量就是99%。
4 新生代GC(Minor GC):发生在新生代的垃圾收集动作,因为java对象大多都具备朝生夕死的特性,所以Minor GC非常频繁,回收比较快。
5 老年代GC(Major GC/Full GC):发生在老年代的GC,出现了Major GC,经常会伴随至少一次的Minor GC(非绝对)。Major GC的速度一般比Minor GC慢10倍。
参考《深入理解java虚拟机》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jwt_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值