在上一节中“JVM(三)内存回收(一)”我讲到了垃圾回收的几种算法,算是解决了之前提到的3个问题中的最后一个。

关于内存回收,还应该了解常用的内存回收器(GC Collector),即执行上述回收算法的引擎。

2. 垃圾回收器(接上章中“怎么回收”)

  2.1 Serial / Serial old 回收器

  从名字的字面意思就能明白,这两个是串行垃圾回收器。请看下图:

  

Serial/Serial Old收集器运行示意图

    从图中可以看出,当到达“安全点”的时候,所有的用户线程都被挂起,即“Stop the world”发生了,然后再由单个GC线程来回收所有不需要使用的对象的内存。这里需要注意的是:

    • 在新生代(serial)中,采用的复制算法进行垃圾回收
    • 在老年代(serial old)中,则是采用的标记-整理算法进行垃圾回收

这两个收集器一般不建议在多处理器的服务器端使用,如果要使用,一般用在内存很小的桌面应用程序或者单核(或少核)的CPU服务器上。

  2.2 ParaNew/ Parallel old/ Parallel Scavenge 回收器

  这三个回收器均为并行回收器,其中,除了Parallel old用于老年代回收外,另外两个都用在新生代。其并行主要体现在:Serial回收器在GC阶段只有单个线程进行GC,而这些回收器,会存在多个GC线程,如下两图:

ParNew/Serial Old收集器运行示意图

Parallel Scavenge/Parallel Old收集器运行示意图

新生代两个并行收集器的主要区别如下:

  • ParaNew 除Serial收集器之外,只有它能和CMS搭配使用;另外,它更注重的是缩短停顿时间,达到更好的用户体验,比较适应用作与用户交互的应用程序上。使用 -XX:+UseConcMarkSweepGC选项默认会被指定为新生代的收集器,而使用-XX:+UseParaNewGC选项来强制指定它为新生代收集器;
  • Parallel Scavenge 则是更注重吞吐量的一个收集器,所谓的吞吐量就是“运行用户代码的时间/(运行用户代码时间+垃圾收集时间)”,主要适合在后台需要大量运算而不需要交互太多的任务。另外一个最大的不同是,该收集器在设定了虚拟机的优化目标之后,如指定了-Xmx,并且指定了MaxGCPauseMillis(更关注最大停顿时间)或GCTimeRatio(更关注吞吐量),再选择参数-XX:+UseAdaptiveSizePolicy,使用自适应功能之后,虚拟机会自动根据收集到的系统性能监控信息,动态调整新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数了,从而提供最合适的停顿时间或者最大的吞吐量。

老年代的并行收集器(Parallel old),是Parallel Scavenge的老年代版本,使用多线程+“标记-整理”算法实现。二者搭配之后,主要用于比较关注高吞吐量、CPU敏感的应用系统。-XX:+UseParallelOldGC来指定。

2.3 CMS 回收器(老年代)

CMS GC (-XX:+UseConcMarkSweepGC),其工作过程比之前的任何一个GC Collector都要复杂,但是对低时延的应用非常有用。下面我们通过和Serial GC对比一下来说明是怎么样做到更低时延的。

从上图中可以看出,CMS一共包含如下4个步骤:

Unmarked objects == Dead Objects

    • Initial Mark(初始标记)这个阶段很快,仅仅是通过GC roots进行简单的可达性分析,会出现和serial GC同样的STW,不过时间非常短,标记出可达对象
    • Concurrent Mark(并行标记)并行标记耗时比较长,但是,从图中可以看出,应用线程是与GC线程同时(并行)执行的,故对用户线程可以认为没有影响;
    • Remark(重新标记)这个阶段会出现短暂的STW暂停,暂停时间比Initial Mark稍微长点,同时其执行时间远比Concurrent Mark要短,主要是修正之前的标记结果,并标记出在Concurrent Mark阶段new出来的一些可达对象
    • Concurrent Sweep(并行清理)将前面3个标记阶段标记出来的需要被清理的对象清除,和(Concurrent Mark)一样,都是和用户线程并行执行的。

由此可见,其低时延的实现原理是,使用户线程能与耗时较长的标记和清除动作并行。

总结一下优点和缺点:

优点:Stop-the-World 时间很短,这很适合做“Responsiveness”应用的垃圾收集器

缺点:

    1. 对CPU和内存的消耗比较大
    2. 对浮动垃圾无法回收(即在并行清理的时候,由用户线程运行所产生的可以被回收的对象)
    3. 容易产生垃圾碎片(从上述过程中,缺省情况下,CMS是没有进行内存整理的,就会造成,看起来还有较多的内存,但是在分配较大对象时,往往可能由于连续内存空间不够,而出发full GC,从而降低JVM的性能)

相关优化的参数:

针对缺点2,在JDK 1.5的默认设置下,CMS收集器当老年代使用了68%的空间后就会被激活,这是一个偏保守的设置,如果在应用中老年代增长不是太快,可以适当调高参数-XX:CMSInitiatingOccupancyFraction的值来提高触发百分比,以便降低内存回收次数从而获取更好的性能,在JDK1.6中,CMS收集器的启动阈值已经提升至92%。要是CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”失败,这时虚拟机将启动后备预案:临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。所以说参数-XX:CM SInitiatingOccupancyFraction设置得太高很容易导致大量“Concurrent Mode Failure”失败,性能反而降低。

针对缺点3,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数(默认就是开启的),用于在CMS收集器顶不住要进行FullGC时开启内存碎片的合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间不得不变长。虚拟机设计者还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,表示每次进入Full GC时都进行碎片整理)。

2.4 G1 回收器

Garbage-First(G1,垃圾优先)收集器是服务类型的收集器,目标是多处理器机器、大内存机器。它高度符合垃圾收集暂停时间的目标,同时实现高吞吐量。Oracle JDK 7 update 4 以及更新发布版完全支持G1垃圾收集器。G1垃圾回集器为以下应用设计:

    • 类似CMS收集器,可以和应用线程同时并发的执行
    • 压缩空闲空间时没有GC引起的暂停时间
    • 需要更可预言的GC暂停时间
    • 不想牺牲大量的吞吐量性能
    • 不需要特别大的Java堆

G1垃圾收集器计划长期替换并发标记清除收集器(CMS,Concurrent Mark-Sweep Collector)。G1和CMS比较,有一些不同点让G1成为一个更好的解决方案。

一个不同点是G1是一个压缩收集器。G1收集器充分地压缩空间以完全避免使用细粒度的空闲列表来分配空间,取而代之的是使用区域。这相当简化了收集器的部件,和尽量消除潜在的碎片问题。

同时,G1收集器相比CMS收集器而言,提供更可预言的垃圾收集暂停时间,允许用户指定想要暂停时间指标。

参考:

原版:http://www.oracle.com/technetwork/tutorials/tutorials-1876574.html

翻译版:http://blog.csdn.net/zhanggang807/article/details/45956325

《深入理解Java虚拟机》

JVM(四)内存回收(二)的更多相关文章

  1. Java技术专题之JVM逻辑内存回收机制研究图解版

    一.引言 JVM虚拟机内存回收机曾迷惑了不少人,文本从JVM实现机制的角度揭示JVM内存回收的原理和机制. 一.Java平台逻辑架构 二.JVM物理结构 通过从JVM物理结构图我们可以看到: 1.JV ...

  2. 图解JVM垃圾内存回收算法

    图解JVM垃圾内存回收算法 这篇文章主要介绍了图解JVM垃圾内存回收算法,由于年轻代堆空间的垃圾回收会很频繁,因此其垃圾回收算法会更加重视回收效率,下面博主和大家来一起学习一下吧 前言 首先,我们要讲 ...

  3. JVM中内存回收深入分析,各种垃圾收集器

    JVM启动有两种模式,client和server 一般JVM启动时会根据主机情况分析选择采用那种模式启动 可发现是server模式 JVM中尤其需要关注的就是HEAP堆区 堆区分为新生代和老年代 新生 ...

  4. Java工作原理:JVM,内存回收及其他

    JAVA虚拟机系列文章 http://developer.51cto.com/art/201001/176550.htm Java语言引入了Java虚拟机,具有跨平台运行的功能,能够很好地适应各种We ...

  5. JVM(四) 垃圾回收

    1. 堆内存结构 Java堆从GC的角度可以细分为:新生代(Eden区.From Survivor区和To Survivor区)和老年代. 1.1 新生代 新生代是用来存放新生的对象.一般占据堆的1/ ...

  6. JVM的内存回收机制

    垃圾回收机制,简称gc.对堆与方法区的对象进行回收,因为java不像c需要编程人员手动clear,虚拟机通过垃圾回收算法,对堆与方法区的对象进行自动回收处理. 1.引用计数法(jvm没有采用,因为当两 ...

  7. JVM的内存区域划分以及垃圾回收机制详解

    在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以 ...

  8. 2 - JVM随笔分类(JVM堆的内存回收)

    JVM常用的回收算法是: 标记/清除算法 标记/复制算法 标记/整理算法 其中上诉三种算法都先具备,标记阶段,通过标记阶段,得到当前存活的对象,然后再将非标记的对象进行清除,而对象内存中对象的标记过程 ...

  9. 深入理解JVM(四) -- 垃圾内存回收的判定方法和内容

    上一篇文章我们学到了对象在内存中是如何存储的已经是如何被访问的,这篇文章将介绍当内存空间不够时,虚拟机将怎样判定对象可不可以被回收已经哪些地方会发生回收. 垃圾回收主要(不是全部)发生在堆内存中,当一 ...

随机推荐

  1. Android学习之旅(一)

    2017-02-27 今天开始,正式开启Android学习之旅,背景从事.Net平台开发快五年了,一直在用C#做Web开发. 前天选购了两本书:<Java 编程思想(第四版)>和<第 ...

  2. 微服务从设计到部署(二)使用 API 网关

    链接:https://github.com/oopsguy/microservices-from-design-to-deployment-chinese 译者:Oopsguy 本书的七个章节是关于设 ...

  3. 永久关闭selinux | 防火墙

    关闭SELinux的两种方法 1 永久方法 – 需要重启服务器 修改/etc/selinux/config文件中设置SELINUX=disabled ,然后重启服务器. 2 临时方法 – 设置系统参数 ...

  4. latex 插图排版

    LaTeX的图片插入及排版   LaTeX中一般只直接支持插入eps(Encapsulated PostScript)格式的图形文件, 因此在图片插入latex文档之前应先设法得到图片的eps格式的文 ...

  5. Vue-上拉加载与下拉刷新(mint-ui:loadmore)一个页面使用多个上拉加载后冲突问题

    所遇问题: 该页面为双选项卡联动,四个部分都需要上拉加载和下拉刷新功能,使用的mint-ui的loadmore插件,分别加上上拉加载后,只有最后一个的this.$refs.loadmore.onTop ...

  6. [2013-03-14]使用wiki维护产品文档

    word文档作为产品文档的问题: word文档本身的设计是为了打印: word文档的编辑较为繁琐: 作为产品文档的word文档往往长达百页以上,难以维护,且容易分散注意力,不利于查阅: 没有一个简单易 ...

  7. 微信H5支付:网络环境未能通过安全验证,请稍后再试。解决办法(PHP版)

    前(tu)言(cao) (这段前言纯属吐槽,着急解决问题的小伙伴,赶紧看正文吧) 最近做了支付宝和微信支付,先做的是PC端网站的支付,就是出个二维码,然后手机扫描支付,当然支付宝在扫码页面支持登录支付 ...

  8. Ubuntu Docker Registry 搭建私有仓库

    服务器版本 Ubuntu 16.04 LTS. 安装命令: $ docker run -d -v /opt/registry:/var/lib/registry -p 5000:5000 --rest ...

  9. 栈的实现Java

    package practice; import java.util.Iterator; //栈 public class MyStack<T> implements Iterable&l ...

  10. 搭建互联网DNS构架

    author:JevonWei 版权声明:原创作品 构建"." DNS."com" DNS及"danran.com",用户通过"电 ...