JVM学习笔记三:垃圾收集器及内存管理策略
垃圾收集器
上文说到了垃圾收集算法,这次我们聊一下HotSpot的具体垃圾收集器的实现,以JDK1.7为例,其包含的可选垃圾收集器如下图:

不同收集器之间的连线,代表它们可以搭配使用,收集器所属的区域代表它们属于新生代收集器还是老年代收集器,下面总结一下每个收集器的特点:
Serial 收集器
Serial 字面意思为串行,这与它的工作方式是有关系的,因为它是一个单线程收集器,他在新生代工作,采取的是复制算法,在单CPU的机器上可以高效的完成收集工作,其对于运行在Client模式下的虚拟机是一个很好的选择。
ParNew收集器
ParNew收集器其实就是Serial收集器的多线程版本,除了采用多线程进行垃圾收集之外,其余行为包括控制参数、收集算法、STW、对象分配法则、回收策略都与Serial收集器完全一样。由于采用多线程ParNew通常是虚拟机运行在Server模式下的首选新生代收集器,ParNew收集器能与CMS收集器配合工作,他默认开启的收集线程数与CPU的数目相同,可以使用-XX:ParallelGCThread 参数设施线程数量
Parallel Scavenge收集器
从名称可以看出Parallel Scavenge也是并行的多线程收集器,工作在新生代,采用复制算法进行收集,那和ParNew相比它有什么特别之处呢?与其他收集器的关注点不同,CMS等收集器的关注点是尽可能的缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是吞吐量,所谓吞吐量是指CPU用于运行用户代码的时间与CPU总消耗时间的比值。如果说实际应用场景,那么CMS等停顿时间较短的收集器适合需要与用户进行交互的程序,以获得良好的响应速度,而Parallel Scavenge收集器具有较高的吞吐量则可以高效的利用CPU时间,尽快完成运算任务,适合后台运算不需要太多交互的任务。
Parallel Scavenge收集器提供了两个参数可以用于精确控制吞吐,分别是最大垃圾收集停顿时间:-XX:MaxGCPauseMillis 以及知己设置吞吐量大小的-XX:FCGCTimeRatio参数,另外还提供了一个自动调节的参数:-XX:PretenureSize
Serial Old收集器
它是Serial收集器的老年代版本,同样是一个单线程收集器,使用标记-整理算法
Parallel Old收集器
他是Parallel Scavenge 收集器的老年代版本,使用标记-整理算法,配合PS收集器使用。
CMS收集器 Concurrent Mark Sweep
CMS是一种以获取最短回收暂停时间为目标的收集器,从名称可以看出CMS是基于标记-整理算法实现的,它的运作过程比较复杂,整个过程分为4个步骤:
- 初始标记 initial mark
这个阶段会扫描root对象直接关联的可达对象。注意不会递归的追踪下去,只是到达第一层而已。这个过程,会STW,但是时间很短。 - 并发标记 concurrent mark
这个阶段是进行真正的GC Tracing,递归分析存活对象,无须STW - 重新标记 remark
需要STW,因为并发标记阶段,用户程序继续运行,所以重写标记那些产生变化的对象。 - 并发删除 concurrent sweep
无须STW,对分析出的死亡对象进行清理。
CMS收集器的缺点
- 对CPU资源敏感
由于并行的特性,需要占用cpu资源,影响用户程序性能,CMS默认启动的回收线程是(CPU数量 + 3)/ 4 当CPU数量小于4个时,CPU数量越少垃圾回收线程占比越大。
- 无法处理浮动垃圾
Floating Garbage,可能会出现Concurrent Mode Failure,而导致另一次Full GC的产生,浮动垃圾是什么,由于并发删除阶段用户线程还在执行,自然还会产生新的垃圾,这部分垃圾在标记步骤之后,所以无法清理,只要等待下一次GC。由于并发的特性,CMS的不能像其他收集器那样等到老年代几乎完全被填满再进行收集,需要预留一部分空间提供并发收集时的用户程序使用,JDK1.5的默认设置是老年代使用了68%的空间后就会被激活,1.6为92%,这个比例可以通过参数 -XX:CMSInitiatingOccupancyFraction来调整,如果GC期间预留的内存空间无法满足用户程序要求,就会出现一次“Concurrent Mode Failure”,这时会启动后备预案,临时启用Serial Old收集器来重新进行老年代的垃圾收集,这样停顿时间就很长了。
- 内存碎片
由于CMS采用标记-删除算法,会产生大量的内存碎片,造成分配大对象时,虽然老年代存在不少剩余空间,但找不到可用的内存空间,不得不提前触发一次Full GC,为了解决这个问题,CMS提供了一个-XX:UseCMSCompactAtFullCollection 开关参数,用于在CMS顶不住进行Full GC时开启内存碎片整理合并,由于整理过程无法并发,所以停顿时间不得不边长,另外还有一个参数-XX:CMDSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,再进行一次带压缩的Full GC,默认为0,表示每次都进行碎片整理。
G1 收集器
Garbage First 是最前沿的收集器之一,在JDK1.7 u4开始商用,它具有如下特点:
1.并发与并行 充分利用多CPU和多核的硬件优势,来缩短STW停顿的时间
2.分代收集,且不需要其他收集器配合就可以独立管理整个Java堆
3.整体上采用标记-整理算法,内部不同Region之间采用复制算法。
4.可预测的停顿,使用者可以指定消耗在垃圾回收上的时间。
比较特别的是G1收集器将整个Java对划分为多个大小相等的独立区域Region,虽然仍然保留新生代和老年代,但已经不再有明显的物理界限,他们只是一部分Region的集合。G1会跟踪各个Region里的垃圾堆积价值大小(回收所获得的空间大小以及所需时间的经验值),维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region。
内存分配与回收策略
- 对象优先在Eden分配
大多数情况下,对象在新生代Eden区中分配,当Eden没有足够空间时,将发生一次MinorGC,虚拟机提供了-XX:PrintGCDetails这个参数,在虚拟机发生垃圾收集时打印内存回收日志,并在内存退出时输出当前的内存各区域分配情况。(MinorGC又称新生代GC,MajorGC/FullGC又称老年代C)。
- 大对象直接进入老年代
java虚拟机提供了一个-XX:PretenureSizeThreshold参数,设置直接在老年代分配的对象的大小,这样可以避免在Eden和两个Survivor区域之间发生大量内存复制。(这个参数只对Serial和ParNew收集器有效)
- 长期存活对象将进入老年代
虚拟机为每个对象定义了一个年龄(Age)计数器,如果对象在Eden区域出生并经过第一次MinorGC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1,对象在Survivor区域熬过一次MinorGC,年龄就加1,当年龄增加到一定程度(默认是15岁),就会被晋升为老年代,这个阀值可以通过参数:-XX:MaxTenuringThreshold设置。
- 动态对象年龄判定
为了更好的适应不同程序的内存情况,虚拟机并不是永远的要求对象的年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代。
- 空间分配担保
在发生MinorGC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的空间,如果这个条件成立,那么MinorGC就是安全的,如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败,如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次MinorGC,尽管这次MinorGC有风险;如果小于,或者HandlePromotionFailure设置不允许冒险,这是也要改为进行一次Full GC。
参考资料
本文参考:《深入理解Java虚拟机》
JVM学习笔记三:垃圾收集器及内存管理策略的更多相关文章
- 《深入java虚拟机》读书笔记之垃圾收集器与内存分配策略
前言 该读书笔记用于记录在学习<深入理解Java虚拟机--JVM高级特性与最佳实践>一书中的一些重要知识点,对其中的部分内容进行归纳,或者是对其中不明白的地方做一些注释.主要是方便之后进行 ...
- JVM基础知识2 垃圾收集器与内存分配策略
如何判断堆中的哪些对象可以被回收 主流的程序语言都是使用根搜索算法(GC Roots Tracing)判定对象是否存活 基本思路是:通过一系列名为“GC Roots”的对象作为起点,从这些节点开始向下 ...
- 深入理解JVM(三)垃圾收集器和内存分配策略
3.1 关于垃圾收集和内存分配 垃圾收集和内存分配主要针对的区域是Java虚拟机中的堆和方法区: 3.2 如何判断对象是否“存活”(存活判定算法) 垃圾收集器在回收对象前判断其是否“存活”的两个算法: ...
- JVM学习笔记——GC垃圾收集器
GC 垃圾收集器 Java 堆内存采用分代回收算法,因此 JVM 针对新生代和老年代提供了多种垃圾收集器. 1. Serial 收集器 Serial 收集器是单线程收集器,采用复制算法. 是最基本的垃 ...
- JVM系列2:垃圾收集器与内存分配策略
垃圾收集是一个很大话题,本文也只是看了深入理解Java虚拟机总结了下垃圾收集的知识. 首先按照惯例,先上思维导图: 垃圾收集简而言之就是JVM帮我们清理掉内存区域不需要的数据.它主要负责清理堆中实例对 ...
- 《深入理解 Java 虚拟机》读书笔记:垃圾收集器与内存分配策略
正文 垃圾收集器关注的是 Java 堆和方法区,因为这部分内存的分配和回收是动态的.只有在程序处于运行期间时才能知道会创建哪些对象,也才能知道需要多少内存. 虚拟机栈和本地方法栈则不需要过多考虑回收的 ...
- 《深入理解Java虚拟机》读书笔记:垃圾收集器与内存分配策略
请移步至:http://zhanjindong.info/2014/05/18/java-gc/
- JVM学习笔记-第三章-垃圾收集器与内存分配策略
JVM学习笔记-第三章-垃圾收集器与内存分配策略 tips:对于3.4之前的章节可见博客:https://blog.csdn.net/sanhewuyang/article/details/95380 ...
- java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)
Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...
随机推荐
- scrapy代理的设置
scrapy代理的设置 在我的上一篇文章介绍了scrapy下载器中间件的使用,这里的scrapyIP的代理就是用这个原理实现的,重写了下载器中间件的process_request(self,reque ...
- loadrunner11的移动端性能测试之脚本录制
以前使用LR11录制过一个app的登录操作,这里记录一下 测试准备 硬件要求 1, 负载测试机一台(内存8G以上,cpu 1.5GHZ以上,存储空间20G以上)或两台以上(控制机和多个负载机). 2 ...
- Jquery DataTables 使用AJAX POST的问题
最近项目在用需要用表格,听说DataTables很好很强大,于是用了一下. Get请求没什么问题,问题处在POST请求上 Jquery原生的POST请求没有问题,代码如下 $.ajax({ url ...
- BigDecimal四舍五入使用总结
//BigDecimal四舍五入double f1 = new BigDecimal(1).setScale(2,RoundingMode.HALF_UP).doubleValue();//转化成字符 ...
- 基于TFS的.net技术路线的云平台DevOps实践
DevOps是近几年非常流行的系统研发管理模式,很多公司都或多或少在践行DevOps.那么,今天就说说特来电云平台在DevOps方面的实践吧. 说DevOps,不得不说DevOps的具体含义.那么,D ...
- 不让bat文件运行命令结束后cmd窗口自动关闭
方法1假设你的bat名字叫aaa.bat你可以新开一个bat,内容是start aaa.bat然后这个新的bat是不会自动关闭的 方法2要执行bat后不退出,可以在bat里的最后添加pause命令,暂 ...
- 【Android Developers Training】 98. 获取联系人列表
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- axis1.4开发webservice服务端(快速入门)-基于jdk1.4
写在前面: 现在有很多开发webservice的方法以及框架,什么cxf等,但是这些在你编写服务类的时候都要用到注解这个功能.如果现在的jdk是1.4的,那么就不能使用注解这个功能了.所以这里可以用到 ...
- 进程间通信之AIDL
一.引言 AIDL是android内部进程通信接口的描述语言,是实现跨进程方法调用的一大利器,其中Binder和Messenger的实现机制都是AIDL. 二.使用下面结合示例说明其使用过程: 本次示 ...
- [图形学] Chp8.4 OpenGL 二维观察函数——视口
这节有几个显示窗口的控制函数,可以调整视口,创建子窗口,最小化为图标,设置图标名称,隐藏显示等. gluOrtho2D (xwmin, xwmax, ywmin, ywmax); // 定义二维裁剪窗 ...