垃圾收集算法和垃圾收集器

垃圾收集算法

(画图的工具使用Gliffy,提供的模块有限使用3(高)*6(宽)的格子来描述算法的思想最理想的是宽为8的格子)

标记-清除算法(Mark-Sweep)

标记-清除算法是最基础的收集算法(之所以叫做基础,是因为后续算法都是基于此针对他的不足改进得到的),如同他的名字一样,分为两个阶段:标记阶段、清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间
如下图:
标记清除

缺点或者不足:效率问题,标记清除效率都不高;另一个是空间问题,容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发新的一次垃圾收集动作。

复制算法(Copying)

为了解决标记清除算法的效率问题,复制算法出现了。
他将可用内存按容量分为等大的两块,每次只是用其中一块,另一块作为保留区域,当一块内存用完了,就将存活的对象复制到另一块上,然后把已使用过的内存空间一次清理掉,如下图:
复制算法
复制算法实现简单,运行高效且不容易产生内存碎片
缺点不足:1.对内存空间的使用做出了高昂的代价,因为能够使用的内存缩减到原来的一半;2.复制算法的效率跟存活对象的数目多少有很大的关系,如果存活对象很多,那么复制算法的效率将会大大降低。

使用:由于他的特性,现代商业虚拟机采用复制算法来回收新生代,IBM公司研究表明,新生代中98%的对象是“朝生夕死”的,所以内存空间不必按照1:1的比例来分配,而是将内存划分为一块较大的Eden空间,两块较小的Survivor空间(HotSpot虚拟机默认Eden空间和Survivor空间的比例为8:1,80% + 10% = 90%),每次使用Eden空间和其中一块Survivor空间,当回收时,先将Eden和Survivor上存活的对象复制到,空闲的Survivor上,然后统一清理Eden空间和刚才是用过的Survivor空间。

但是,新生代98%的对象可回收针对一般场景,没有办法保证每次都有不多于10%的对象存活(当另一块Survivor空间不够用来存放上一次新生代收集的存活对象时,这些对象需要被分配进入担保内存),所以需要其他内存(老年代)进行分配担保。

标记-整理算法(Mark-Compact)

和复制算法不同,标记-整理算法是针对老年代特点(存活率较高)的算法,充分利用空间,标记过程和“标记-清除算法”中的过程一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。如下图:

标记整理

老年代的垃圾回收器(例如 Serial Old,Parallel Old,不包括CMS,CMS使用的是标记清除法)都是采用这个算法,主要由于老年代的对象都比较持久,不是短暂的。

分代收集算法(Generational Collection)

根据对象存货周期的不同划分为几块,一般把堆分为新生代和老年代,还有一块区域被称为永久代即方法区(非堆,它的回收主要是针对废弃常量和无用类)。
在新生代中,每次垃圾回收时有大量对象死去,只有少量存活,那就选择“复制算法”,只需要付出少量对象的复制成本就可以完成收集。
在老年代中,存活率高,没有额外的空间对它分配担保,就必须使用“标记清除”或者“标记整理”来回收。

垃圾收集器

此处讨论的垃圾收集器基于《深入理解Java虚拟机》中所依赖的Java 7 update14之后的HotSpot虚拟机(在这个版本中正式提供了G1(Garbage First)收集器),一共七种,Serial和Serial Old在一起介绍。

先来一张图:

HotSpot虚拟机新生代老年代收集器划分搭配图

1.Serial/Serial Old

  Serial/Serial Old收集器是最基本最古老的收集器(JDK1.3.1之前版本),它是一个单线程收集器,并且在它进行垃圾收集时,必须暂停所有工作线程(Stop The World)。Serial收集器是针对新生代的收集器,采用的是Copying算法,Serial Old收集器是针对老年代的收集器,采用的是Mark-Compact算法。它的优点是实现简单高效,但是缺点是会给用户带来停顿。

2.ParNew

  ParNew收集器是Serial收集器的多线程版本,使用多个线程进行垃圾收集。

3.Parallel Scavenge(吞吐量优先收集器)

  Parallel Scavenge收集器是一个新生代的多线程收集器(并行收集器),它在回收期间不需要暂停其他用户线程,其采用的是Copying算法,该收集器与前两个收集器有所不同,它主要是为了达到一个可控的吞吐量(吞吐量:就是CPU用于运行用户代码的时间与CPU总耗时的比值 吞吐量 = 运行用户代码时间/(运行用户代码时间+垃圾回收时间),比如虚拟机总共运行100分钟,垃圾回收用了1分钟,吞吐量是99%吞吐量越高应用程序交互性越好)。

4.Parallel Old

  Parallel Old是Parallel Scavenge收集器的老年代版本(并行收集器),使用多线程和Mark-Compact算法。(JDK1.6中提供)

5.CMS

  CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,并发收集、低停顿,它是一种并发收集器,采用的是Mark-Sweep算法。
步骤交标记清除复杂有四步:
①初始标记
②并发标记
③重新标记
④并发清除
缺点:
①对CPU资源敏感(占用CPU资源较多)。
②无法处理浮动辣鸡(Floating Garbage,即在垃圾回收是又产生的一部分垃圾,在当次回收时无法处理只能留待下次处理),可能出现Concurrent Mode Failure失败,从而触发另一次FullGC。
③标记清除产生大量碎片。
6.G1
详细参考:新一代垃圾回收算法增量收集算法和G1收集算法
  G1(Garbage First)收集器是当今收集器技术发展最前沿的成果,它是一款面向服务端应用的收集器,它能充分利用多CPU、多核环境。因此它是一款并行与并发收集器,并且它能建立可预测的停顿时间模型。

特点:并行与并发  分代收集  空间整合  可预测停顿
步骤: ①初始标记 ②并发标记 ③最终标记 ④筛选回收

  下面补充一下关于内存分配方面的东西:
  
  对象的内存分配,往大方向上讲就是在堆上分配,对象主要分配在新生代的Eden Space和From Space,少数情况下会直接分配在老年代。如果新生代的Eden Space和From Space的空间不足,则会发起一次GC,如果进行了GC之后,Eden Space和From Space能够容纳该对象就放在Eden Space和From Space。在GC的过程中,会将Eden Space和From Space中的存活对象移动到To Space,然后将Eden Space和From Space进行清理。如果在清理的过程中,To Space无法足够来存储某个对象,就会将该对象移动到老年代中。在进行了GC之后,使用的便是Eden space和To Space了,下次GC时会将存活对象复制到From Space,如此反复循环。当对象在Survivor区躲过一次GC的话,其对象年龄便会加1,默认情况下,如果对象年龄达到15岁,就会移动到老年代中。

  一般来说,大对象会被直接分配到老年代,所谓的大对象是指需要大量连续存储空间的对象,最常见的一种大对象就是大数组,比如:

  byte[] data = new byte[4*1024*1024]

  这种一般会直接在老年代分配存储空间。

  当然分配的规则并不是百分之百固定的,这要取决于当前使用的是哪种垃圾收集器组合和JVM的相关参数。

参考:
《深入理解Java虚拟机》第二版
推荐要看的虚拟机方面的知识
垃圾回收算法和垃圾收集器
新一代垃圾回收算法增量收集算法和G1收集算法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值