JVM学习记录-垃圾收集器
先回顾一下上一篇介绍的JVM中常见几种垃圾收集算法:
- 标记-清除算法(Mark-Sweep)。
- 复制算法(Copying)。
- 标记整理算法(Mark-Compact)。
- 分代收集算法(Generational Collecting)。
如果说收集算法是内存回收的方法论。那么垃圾收集器就是内存回收的具体实现。不同的厂商、不同的版本的虚拟机提供的垃圾收集器会有很大差别,目前讨论的收集器基于JDK1.7 Update 14之后的HotSpot虚拟机。这个虚拟机包含的所有垃圾收集器以及其作用范围如图:
7种作用于不同分代的收集器,可以连线的两个说明可以搭配使用。不同的收集器作用于不同的分代,这是说明没有一个收集器能在任何场景下都完美适用,肯定都是有舍有得,通过了解和分析垃圾回收器是就是为了让我们选择出对具体应用最合适的收集器。
Serial收集器
Serial收集器是发展历史最悠久的收集器,在jdk1.3之前是新生代唯一的选择,它是一个单线程收集器,单线程并不代表在进行垃圾回收时会只用一个线程去进行垃圾回收,而重要的是在它进行垃圾收集时,必须暂停其他所有线程,直到收集结束。这就是传说中的“Stop The World”。
运行示意图如下:
虽然这个过程是一个用户不可见的执行过程,但是确实也给用户带来了不良体验,从Serial到G1目前都还没有办法彻底消除停顿时间。Serial收集器虽然有这个大弊端,但是对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。对于运行在Client模式下的虚拟机来说Serial收集器是一个很好的选择。
ParNew收集器
ParNew收集器其实是Serial收集器的多线程版本,除了使用了多线程进行垃圾收集之外,其他的内容大致和Serial一样,例如:配置参数、收集算法、Stop The World对象分配规则、回收策略等。在实现上大部分代码也重合。而且ParNew收集器也是作用在新生代。
运行示意图如下:
ParNew收集器除了多线程收集之外,其他与Serial收集器相比并没有太多创新,但它趋势许多运行在Server模式下的虚拟机中首选的新生代收集器,其中有一个与性能无关但很重要的原因是除了Serial收集器外,目前只有它能与CMS收集器配合工作。
Parallel Scavenge收集器
Parallel Scavenge收集器也是一个新生代收集器,使用的复制算法,并且也是多线程并行收集器,功能上和ParNew收集器类似,但是两者个关注点是不同的,ParNew等收集器的关注点是尽可能的缩短用户线程的停止时间,而Parallel Scavenge收集器的关注点是让JVM达到一个可控制的吞吐量。所谓吞吐量就是:CPU运行用户代码的时间与CPU消耗时间的比值。即吞吐量 = 运行用户代码时间/(运行用户代码时间+垃圾收集时间),运行用户代码时间99分钟,垃圾收集时间1分钟,那吞吐量就是99%。
Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。
MaxGCPauseMillis参数允许的值是一个大于0的毫秒数。
GCTimeRatio参数的值应当是一个大于0且小于100的整数,即垃圾收集时间占总时间的比率,默认99,就是允许最大1%(1/(1+99))的垃圾收集时间。
运行示意图如下:
Serial Old收集器
Serial Old收集器是运行在老年代的收集器,相当于Serial的老年代版本,也是单线程收集器。使用的“标记-整理”算法,主要也是Client模式下的虚拟机使用(单个CPU的环境),在Server模式下主要还有两大用途:一是在JDK1.5以及之前的版本中与Parallel Scavenge收集器搭配使用,二是作为CMS收集器的后备预案。
Serial Old 收集器运行示意图如下:
Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。在JDK1.6中才开始提供,在此之前,新生代选择了Parallel Scavenge收集器,老年代只能选择Serial Old,因为Parallel Scavenge是多线程收集器,但是到了老年代只能用Serial Old收集器,这样相当于只能在新生代达到提高吞吐量的效果。直到老年代也提供了这种以提高吞吐量为主的收集器,新生代使用Parallel Scavenge收集器,老年代使用Parallel Old收集器就形成了以吞吐量优先的收集器组合。在注重吞吐量以及CPU资源敏感的场合,可以优先考虑这种场合。
Parallel Old收集器运行示意图如下:
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以缩短回收停顿时间为目标,并且适用于老年代的收集器。
它运作过程相对复杂一些,主要分为4个步骤:
- 初始标记(CMS inital mark)
- 并发标记 (CMS concurrent mark)
- 重新标记 (CMS remark)
- 并发清除 (CMS concurrent sweep)
初始标记和重新标记是需要线程停顿的。初始标记仅仅只是标记一些GC Roots能直接关联到对象,并发标记是进行GC Roots Tracing(追踪)的过程,而重新标记是为了修正并发标记时因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。
运行过程示意图如下:
CMS收集器的优点从运行过程中就可以看出来,并发收集,低停顿。并发标记和并发清除可以和用户线程一起运行这样也是降低了用户应用程序的停顿时间。
但是CMS收集器也还是远远没有达到完美的程度, 它有以下3个明显的缺点:
CMS收集器对CPU资源非常敏感。在并发标记和并发清除时是和用户线程一起运行的,收集过程中肯定占用了用户程序的CPU资源。默认启动的回收线程数是(cpu数量+3)/4,当cpu数较少的时候,会分掉大部分的cpu去执行收集器线程,影响用户,降低吞吐量。
CMS收集器无法处理浮动垃圾。在并发清除阶段,用户程序并没有停止,所以还会继续产生垃圾,而这部分垃圾只能等待着下一次收集时才能进行回收。
CMS收集器会产生空间碎片。因为CMS收集器是基于“标记-清除”算法实现的,所以在进行大量的垃圾回收时,会产生很多不连续的内存空间。这是使用“标记-清除”算法都会有的缺点。
G1收集器
G1(Garbage First)收集器是目前最新的收集器了,java9以及java10默认的垃圾收集器就是G1。在JDK6u14中就有Early Access版本的G1收集器提供开发人员试用。到JDK 7u4才算是正是发布。G1是基于“标记-整理”算法来实现的,可以独立的维护新生代以及老年代两个部分。
与其他的GC收集器相比,G1有如下特点:
并行与并发,G1充分利用多CPU资源来缩短停顿时间,即执行GC过程中用户程序扔可继续执行。
分代收集,虽然G1可以不需要与其他收集器配合就可以独立管理整个GC堆,但分代感念在G1中依然保留,这样可以让G1采用不同的方式来处理新生代和老年代的对象。
空间整合,因为G1是基于“标记-整理”算法实现的,所以不会产生空间碎片,内存空间很好的整合起来了。
可预测的停顿,这个特点是相对CMS收集器的一个优势,G1可以让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在牢记收集上的时间不得超过N秒。
前面介绍的几个收集器,要么是作用在新生代,要么是作用在老年代,G1作用于整个堆,它将整个堆分为多个大小相等的独立区域(Region),虽然仍保留了分代,但不再是物理隔离,都是一部分Region的集合。
G1收集器运行过程大致分为以下几步:
- 初始标记
- 并发标记
- 最终标记
- 筛选回收
初始标记阶段和CMS收集器类似,也是仅仅标记一下GC Roots能直接关联到的对象,并且修改TAMS(Next Top at Mark Start)的值,让下一阶段用户程序并发运行时可以在正确的Reginon中创建新对象。并发标记阶段是对堆中对象进行可达性分析,找出存活对象,这个阶段可以与用户线程并发进行,而最终标记阶段是为了修正在并发标记期间因为用户程序并发运行,而导致标记产生变动的那部分标记记录,这阶段需要用户线程停顿,但是可并发进行。在最后的筛选回收阶段首先对各个Region的回收价值和成本进行排序,然后根据用户所期望的GC停顿时间来制定回收计划。
运行过程示意图如下:
JDK目前有的这些收集器差不多都介绍完了,下面来看看各个版本的JDK默认的都是使用的什么垃圾收集器吧。
这段代码是打印出当前jdk中使用的是什么垃圾回收器
@org.junit.Test
public void myTestGC(){
List<GarbageCollectorMXBean> list =
ManagementFactory.getGarbageCollectorMXBeans();
for(GarbageCollectorMXBean gb:list){
System.out.println("垃圾回收器:"+gb.getName());
}
}
我的的IDEA目前配置的jdk版本是jdk1.8.0_144,运行结果如下:
PS Scavenge代表的是Parallel Scavenge收集器,PS MarkSweep 代表的是Parallel Old收集器(一开不知道是表示的Parallel Old还跑到知乎上面去提问,结果还是自己找到的答案)这说明JDK8默认使用的是以吞吐量优先的这两个手机器组合。
下面我把IDEA的JDK版本换成JDK9,运行结果如下:
这个就可以直接了当的看出来 了,JDK9默认的垃圾收集器是G1。
下面我把IDEA的JDK版本换成JDK10,运行结果如下:
这说明JDK10默认的垃圾收集器也是G1。
下面我把IDEA的JDK版本换成JDK1.7,运行结果如下:
这表示JDK1.7默认的垃圾收集器也是Parallel Scavenge和Parallel Old。
因为下载不到JDK1.6以及再之前的JDK了,所以就先看这几个版本的吧。如果找到了,后续再补上。
JVM学习记录-垃圾收集器的更多相关文章
- JVM学习记录-类加载器
前言 JVM设计团队把类加载阶段中的“通过一个类的全限定名来获取描述此类的二进制字节流”这个动作放到Java虚拟机外面去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码模块称为“类 ...
- 【JVM】JVM中的垃圾收集器
垃圾收集器组合 Serial+Serial Old Serial+CMS ParNew+CMS ParNew+Serial Old Paralle Scavenge + Serial Old Para ...
- Java虚拟机JVM学习05 类加载器的父委托机制
Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...
- Spark学习之路 (十四)SparkCore的调优之资源调优JVM的GC垃圾收集器
一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...
- JVM学习记录3--垃圾收集器
贴个图 Serial收集器 最简单的收集器,单线程,收集器会暂停用户线程,称为"stop the world". ParNew收集器 Serial收集器的多线程版本,其它类似.默认 ...
- JVM学习记录
本博客是为了自己学习JVM而建立,只记录一些自己学习的经过. 最近在看<深入理解Java虚拟机>这本书,里面的内容,很是乏味,因为看不懂所以就会觉得很枯燥,觉得很枯燥看着看着就犯困,然后就 ...
- JVM优化之垃圾收集器以及内存分配
在jvm中,实现了多种垃圾收集器,包括:串行垃圾收集器.并行垃圾收集器.CMS(并发)垃圾收集器.G1垃圾收集器,接下来,我们一个个的了解学习. 串行垃圾收集器 串行垃圾收集器,是指使用单线程进行垃圾 ...
- jvm七种垃圾收集器
JVM_七种垃圾收集器介绍 本文中的垃圾收集器研究背景为:HotSpot+JDK7 一.垃圾收集器概述 如上图所示,垃圾回收算法一共有7个,3个属于年轻代.三个属于年老代,G1属于横跨年轻代和年老 ...
- jvm系列 (二) ---垃圾收集器与内存分配策略
垃圾收集器与内存分配策略 前言:本文基于<深入java虚拟机>再加上个人的理解以及其他相关资料,对内容进行整理浓缩总结.本文中的图来自网络,感谢图的作者.如果有不正确的地方,欢迎指出. 目 ...
随机推荐
- 【44】java大数值剖析
基本的整数和浮点型精度不能满足需求,那么可以使用java.math中的两个类:BigInteger和BigDecimal. BigInteger和BigDecimal介绍: 这两个类可以处理包含任意长 ...
- 关于UIView用户交互相关的属性和方法
UIView除了负责展示内容给用户外还负责响应用户事件 1.交互相关的属性 userInteractionEnabled 默认是YES ,如果设置为NO则不响应用户事件,并且把当前控件从事件队列中删除 ...
- leetCode之旅(5)-博弈论中极为经典的尼姆游戏
题目介绍 You are playing the following Nim Game with your friend: There is a heap of stones on the table ...
- ruby TkPackage can't find package BWidget 之解决办法
一个特别短的ruby/tk代码: require 'tkextlib\iwidgets' require 'tkextlib\bwidget' x = 0 101.times {|i| x+=i} T ...
- WebService学习--(一)webservice相关概念
一.序言 大家或多或少都听过 WebService(Web服务),有一段时间很多计算机期刊.书籍和网站都大肆的提及和宣传WebService技术,其中不乏很多吹嘘和做广告的成 分.但是不得不承认的是W ...
- iOS开发常用第三方库
UI 动画 网络相关 Model 其他 数据库 缓存处理 PDF 图像浏览及处理 摄像照相视频音频处理 响应式框架 消息相关 版本新API的Demo 代码安全与密码 测试及调试 AppleWatch ...
- 继续死磕SDRAM控制器
SDRAM控制器 博主上一篇介绍了一些SDRAM的基本原理是否有必要学习使用纯Verilog写一个SDRAM控制器,接下来记录SDRAM控制器的工作原理.首先是上电初始化. 上电初始化 时序图中,tR ...
- ajax调用servlet
1.利用myecilpse建立一个web项目 2.导入需要的包: commons-beanutils.jar commons-collections-3.1.jar commons-lan ...
- JDK 常用命令
一) 引言: 当我们安装完JDK时,除了必须的编译运行以外,它就已经自带了很多辅助工具.正所谓“工欲善其事,必先利其器.”如果能用好这些工具,它们将大大方便你的开发.它们的实用和方便有时甚至会使 ...
- java.lang.SecurityException: Can't make field constructor accessible
原本使用GsonConvertor,在Android版本5.1.1上没有任何问题,结果切换到版本6.0.1上,出现以下所示问题: java.lang.IllegalArgumentException: ...