垃圾收集器

对于程序计数器、虚拟机栈、本地方法栈随着线程而生,随着线程而灭,在这几个区域内就不需要过多的考虑垃圾回收的问题,因为方法结束或线程结束后,内存自然就跟着收回了。而java堆和方法区则不一样,压机回收器所关注的也是这部分内存。

1. 如何判断对象已死?

1.1 引用计数算法

    引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器值为0的对象就是不可能再被使用的。

虽然该方法简单,效率也可以,但是主流的java虚拟机里面没有使用该方法来管理内存的,原因:它难以解决对象之间相互循环引用的问题

1.2 可达性分析算法

   可达性分析算法:其基本思路就是通过一系列的称为“GC Roots” 的对象作为起始点,从这些节点开始向下搜索,所走过的路径称为引用链,当一个对象到“GC Roots” 没有任何引用链相连时,则证明对象是不可用的。

2. 垃圾收集算法

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

      标记-清除算法时最基础的收集算法,算法分为 标记  和 清除 两个阶段,首先标记处所有要回收的对象,在标记完成后统一回收所有被标记的对象。该算法主要不足有两个:

一是效率问题,标记和清除两个过程的效率都不高,另一个是空间问题标记清除之后会产生大量的内存碎片,空间碎片太多可能导致以后程序在运行过程中需要分配较大内存时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

2.2 复制算法

    为了解决效率问题,复制算法就出现了。他将可用的内存容量分为相等的两部分,每次只是用其中的一块,当这一块的内存使用完了,就将还存活的对象复制到另一块内存中,然后将这一块内存一次性清理掉。该算法的代价:将内存缩小为原来的一半。

      现在的商业虚拟机都采用这中算法来回收新生代,研究表明,新生代中的对象98%是朝生夕死,所以不需要按照1:1的比例来划分内存。而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活的对象,一次型复制到另一块Survivor中,最后清理掉Eden和用过的那个Survivor。如果另外一块Survivor空间没有足够的内存空间存放存活对象,这些对象直接通过分配担保机制进入老年代。HotSpot默认的Eden :Survivor = 8:1,也就是每次新生代中可用的内存为整个新生代的90%。

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

      该算法的标记过程仍然和  标记-清除算法一样,但是后面不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

2.4 分代收集(Generational Collection)算法

     当前商业虚拟机的垃圾收集都采用“分代收集”算法,该算法根据对象的存活周期的不同将内存划分为几块。一般是将堆分为新生代和老年代。这样就可以根据各个年代的特点采用最合适的收集算法。


3. 垃圾收集器

     如果说垃圾收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。

补充一下并发和并行的概念:

  并行:指多条垃圾收集线程并行工作,但此时的用户线程仍然处于等待状态。

  并发:指用户线程与垃圾收集线程同时执行(但不一定是并行,可能是交替进行),用户程序在继续运行,而垃圾收集程序运行在另一个CPU上。

补充一下吞吐量:吞吐量就是CPU运行用户代码的时间与CPU总消耗时间的比值,即吞吐量= 运行用户代码时间/(运行用户代码时间+垃圾收集时间)。

3.1 Serial 收集器

      Serial收集器是最基本、发展历史最悠久的收集器,他是一个单线程的收集器,它的“单线程” 的意义并不仅仅说明他只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是他在进行垃圾收集时,必须暂停其它所有的工作线程,直到它收集结束。Serial收集器对于运行在Cilent 模式下的虚拟机来说是一个很好的选择。


3.2 ParNew 收集器

     ParNew收集器 其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余都一样。ParNew是许多运行在Server模式下的虚拟机中首选的新生代收集器,因为目前除了Serial 收集器外,目前只有他能与CMS 收集器配合工作。


3.3 Parallel Scavenge收集器

     Parallel Scavenge 收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器。

     Parallel Scavenge 收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge 收集器 的目标是达到一个可控制的吞吐量。

3.4 Serial Old收集器

    Serial Old 收集器是老年代版本,单线程收集器,采用“标记-整理”算法。这个收集器的主要意义也是在于给Cilent 模式下的虚拟机使用,在Server模式下,他主要还有两大用途:一种用途是 在JDK5及之前的版本中与Parallel Scavengr 收集器搭配使用,另一种用途就是作为CMS收集器的后备预案。

3.5 Parallel Old 收集器

     Parallel  Old 是Parallel  Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法。开始于JDK6,在注重吞吐量以及CPU 资源敏感的场合,都可以优先考虑Parallel Scavenge 和Parallel Old 收集器。

3.6 CMS 收集器

     CMS(Concurrent - Mark - Sweep )收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统的停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。

    CMS收集器是基于“标记-清除算法”实现的,整个过程分为4步:

                                                              初始标记  -->并发标记 -->重新标记 -->并发清除

其中,初始标记和重新标记这两个步骤仍然需要 “Stop The World”。但是整个过程中用时最长的并发标记和并发清除过程垃圾收集器线程是可以与用户线程一起工作的,所以总体上来说,CMS收集器的线程是与用户线程一起并发工作的。

   CMS收集器的优点是:并发收集,低停顿。缺点:CMS收集器对CPU资源非常敏感;CMS收集器无法处理浮动垃圾;CMS收集器基于标记-清除 算法实现的,收集结束时会有大量的空间碎片产生。为了解决这个问题,CMS提供了一个参数,用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理过程。

3.7 G1(Garbage - First)收集器

     G1被视为JDK7中HotSpot虚拟机的一个重要进化特征。

    G1是一款面向服务端应用的垃圾收集器。与其他GC相比,G1具有如下特点:

    并行与并发:G1充分利用多CPU、多核环境下的硬件优势,,使用多个CPU来缩短 Stop The World 的停顿时间。

    分代收集:虽然G1可以不需要其他收集器配合就能独立的管理整个GC堆,但是他可以采用不同的方式去处理新创建的对象,已经存活了一段时间的对象,熬过多次GC的旧对象以获取更好的收集效果。

    空间整合:G1从整体上来看是基于 “标记-整理”算法实现的,但从局部上来看是基于“复制”算法实现的。这意味着G1运作期间不会产生内存空间碎片。

    可预测停顿:这是G1相对于CMS的另一大优势,降低停顿时间是G1和CMS 共同的关注点,但是G1除了追求低停顿外,还能建立可预测的停顿时间模型。

     使用G1收集器时,java堆的内存布局与其他收集器有很大的不同,它将整个堆划分为大小相等的多个独立区域(Region),虽然还保留有新生代和老年代的概念,但他们不再是物理隔离的了,他们都是一部分Region(不需要连续)的集合。G1优先收集价值最大的Region(这也是Garbage - First的由来)。




   


 

  








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值