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),大部分人都把这项 ...
随机推荐
- mac os 安装 python 环境
1.我们先获取pip安装脚本: 1 wget https://bootstrap.pypa.io/get-pip.py 如果没有安装wget可以去这里将所有内容复制下来,新建get-pip.py文件, ...
- CSharpGL(42)借助帧缓存实现渲染到纹理(RenderToTexture)
CSharpGL(42)借助帧缓存实现渲染到纹理(RenderToTexture) 渲染到纹理(Render To Texture)是实现很多OpenGL高级效果的一个基础.本文记录了如何用CShar ...
- grub2详解(翻译和整理官方手册)
翻译了grub2官方手册的绝大部分内容,然后自己整理了一下.因为内容有点杂,所以章节安排上可能不是太合理,敬请谅解. 本文目录: 1.1 基础内容 1.2 安装grub2 1.3 grub2配置文件 ...
- 如何卸载CentOS自带的apache
查看安装的组件: rpm -qa | grep httpd 如果预装有apache,那么会显示像httpd-2.2.3-22.el5.centos这种的组件名. 卸载组件: rpm -e httpd- ...
- php变量双击选择无法选择$符号
创建/Data/Packages/User/PHP.sublime-settings文件,内容为 { "word_separators": "./\\()\&qu ...
- java注解编程
- IOS开发基础环境搭建
一.目的 本文的目的是windows下IOS开发基础环境搭建做了对应的介绍,大家可根据文档步骤进行mac环境部署: 二.安装虚拟机 下载虚拟机安装文件绿色版,点击如下文件安装 获取安装包: ...
- String详细学习
学这些东西,就像是扎马步.小说里郭靖学不会招数,就会扎马步.搞JS,内力还是必须要深厚,深厚,深厚. 1,stringObject.slice(start,end) slice() 方法可提取字符串的 ...
- Python3中文件处理
1.txt,xls,doc等文件的使用 f=open("filename","w") 打开一个用于写入的文件,要写入内容时使用f.write("内 ...
- .net入门 - Get Started with .NET
阅读原文 有很多种方式去开始使用.net.因为.net是一个巨大的平台,在这个文档里面有很多文章,告诉你如何从不同的角度去开始使用.net. 使用.NET的语言入门 C#入门文章和C#教程提供了以C# ...