JAVA分代收集机制详解

JVM 新生代为何需要两个 Survivor 空间?
我们知道,目前主流的虚拟机实现都采用了分代收集的思想,把整个堆区划分为新生代和老年代;新生代又被划分成 Eden 空间、 From Survivor 和 To Survivor 三块区域。
看书的时候有个疑问,为什么非得是两个 Survivor 空间呢?要回答这个问题,其实等价于:为什么不是0个或1个 Survivor 空间?为什么2个 Survivor 空间可以达到要求?
为什么不是0个 Survivor 空间?
这个问题等价于:为什么需要 Survivor 空间。我们看看如果没有 Survivor 空间的话,垃圾收集将会怎样进行:一遍新生代 gc 过后,不管三七二十一,活着的对象全部进入老年代,即便它在接下来的几次 gc 过程中极有可能被回收掉。这样的话老年代很快被填满, Full GC 的频率大大增加。我们知道,老年代一般都会被规划成比新生代大很多,对它进行垃圾收集会消耗比较长的时间;如果收集的频率又很快的话,那就更糟糕了。基于这种考虑,虚拟机引进了“幸存区”的概念:如果对象在某次新生代 gc 之后任然存活,让它暂时进入幸存区;以后每熬过一次 gc ,让对象的年龄+1,直到其年龄达到某个设定的值(比如15岁), JVM 认为它很有可能是个“老不死的”对象,再呆在幸存区没有必要(而且老是在两个幸存区之间反复地复制也需要消耗资源),才会把它转移到老年代。
总之,设置 Survivor 空间的目的是让那些中等寿命的对象尽量在 Minor GC 时被干掉,最终在总体上减少虚拟机的垃圾收集过程对用户程序的影响。
为什么不是1个 Survivor 空间?
回答这个问题有一个前提,就是新生代一般都采用复制算法进行垃圾收集。原始的复制算法是把一块内存一分为二, gc 时把存活的对象(Eden和Survivor to)从一块空间(From space)复制到另外一块空间(To space),再把原先的那块内存(From space)清理干净,最后调换 From space 和 To space 的逻辑角色(这样下一次 gc 的时候还可以按这样的方式进行)。
我们知道,在 HotSpot 虚拟机里, Eden 空间和 Survivor 空间默认的比例是 8:1 。我们来看看在只有一个 Survivor 空间的情况下,这个 8:1 会有什么问题。此处为了方便说明,我们假设新生代一共为 9 MB 。对象优先在 Eden 区分配,当 Eden 空间满 8 MB 时,触发第一次 Minor GC 。比如说有 0.5 MB 的对象存活,那这 0.5 MB 的对象将由 Eden 区向 Survivor 区复制。这次 Minor GC 过后, Eden 区被清理干净, Survivor 区被占用了 0.5 MB ,还剩 0.5 MB 。到这里一切都很美好,但问题马上就来了:从现在开始所有对象将会在这剩下的 0.5 MB 的空间上被分配,很快就会发现空间不足,于是只好触发下一次 Minor GC 。可以看出在这种情况下,当 Survivor 空间作为对象“出生地”的时候,很容易触发 Minor GC ,这种 8:1 的不对称分配不但没能在总体上降低 Minor GC 的频率,还会把 gc 的时间间隔搞得很不平均。把 Eden : Survivor 设成 1 : 1 也一样,每当对象总大小满 5 MB 的时候都必须触发一次 Minor GC ,唯一的变化是 gc 的时间间隔相对平均了。
上面的论述都是以“新生代使用复制算法”这个既定事实作为前提来讨论的。如果不是这样,比如说新生代采用“标记-清除”或者“标记-整理”算法来实现幸存对象的移动,好像确实是只需要一个 Survivor 就够了。至于主流的虚拟机实现为什么不考虑采用这种方式,我也不是很清楚,或许有实现难度、内存碎片或者执行效率方面的考虑吧。
为什么2个 Survivor 空间可以达到要求?
问题很清楚了,无论 Eden 和 Survivor 的比例怎么设置,在只有一个 Survivor 的情况下,总体上看在新生代空间满一半的时候就会触发一次 Minor GC 。那有没有提升的空间呢?比如说永远在新生代空间满 80% 的时候才触发 Minor GC ?
事实上是可以做到的:我们可以设两个 Survivor 空间( From Survivor 和 To Survivor )。比如,我们把 Eden : From Survivor : To Survivor 空间大小设成 8 : 1 : 1 ,对象总是在 Eden 区出生, From Survivor 保存当前的幸存对象, To Survivor 为空。一次 gc 发生后:
1)Eden 区活着的对象 + From Survivor 存储的对象被复制到 To Survivor ;
2) 清空 Eden 和 From Survivor ;
3) 颠倒 From Survivor 和 To Survivor 的逻辑关系: From 变 To , To 变 From 。
可以看出,只有在 Eden 空间快满的时候才会触发 Minor GC 。而 Eden 空间占新生代的绝大部分,所以 Minor GC 的频率得以降低。当然,使用两个 Survivor 这种方式我们也付出了一定的代价,如 10% 的空间浪费、复制对象的开销等。
JAVA分代收集机制详解的更多相关文章
- 【转】java的动态代理机制详解
java的动态代理机制详解 在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们 ...
- java的动态代理机制详解-----https://www.cnblogs.com/xiaoluo501395377/p/3383130.html
java的动态代理机制详解-----https://www.cnblogs.com/xiaoluo501395377/p/3383130.html
- java 深拷贝与浅拷贝机制详解
概要: 在Java中,拷贝分为深拷贝和浅拷贝两种.java在公共超类Object中实现了一种叫做clone的方法,这种方法clone出来的新对象为浅拷贝,而通过自己定义的clone方法为深拷贝. (一 ...
- Java的内存回收机制详解X
http://blog.csdn.net/yqlakers/article/details/70138786 1 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前 ...
- Java并发之Synchronized机制详解
带着问题阅读 1.Synchronized如何使用,加锁的粒度分别是什么 2.Synchronized的实现机制是什么 3.Synchronized是公平锁吗 4.Java对Synchronized做 ...
- 初识JVM:(二)Java的垃圾回收机制详解
声明:本文主要参考https://www.cnblogs.com/codeobj/p/12021041.html 仅供个人学习.研究之用,请勿用于商业用途,如涉及侵权,请及时反馈,立刻删除. 一.Ja ...
- JAVA中的GC机制详解
优秀Java程序员必须了解的GC工作原理 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只 ...
- java虚拟机垃圾回收机制详解
首先,看一下java虚拟机运行的时候内存分配图: jvm虚拟机栈:一个是线程独有的,每次启动一个线程,就创建一个jvm虚拟机栈,线程退出的时候就销毁.这里面主要保存线程本地变量名和局部变量值. 本地方 ...
- java的动态代理机制详解
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
随机推荐
- windows下安装redis并设置自启动
一.下载windows版本的Redis 去官网找了很久,发现原来在官网上可以下载的windows版本的,现在官网以及没有下载地址,只能在github上下载,官网只提供linux版本的下载 官网下载地址 ...
- Spring源码分析(二十四)初始化非延迟加载单例
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 完成BeanFactory的初始化工作,其中包括ConversionS ...
- kubernetes 日志定制查阅 - 排错 -- 好用的命令
You can use kubectl logs to retrieve logs from a previous instantiation of a container with --previo ...
- STL容器与拷贝构造函数
所有容器提供的都是“value语意”而非“reference语意”.容器内进行元素的安插操作时,内部实施的是拷贝操作,置于容器内.因此STL容器 的每一个元素都必须能够拷贝.---<<C+ ...
- JavaWeb基础—HTML小结
---是什么?超文本标记语言---能干什么?描述网页的一种语言---怎么干?一套标签 前端三剑客的关系: 1. HTML是网页内容的载体. 2. CSS样式是表现. 3. JavaScript是用来实 ...
- 20155217 《信息安全系统设计基础》week16课堂测试
20155217 <信息安全系统设计基础>week16课堂测试 在作业本上完成附图作业,要认真看题目要求并提交作业截图. 在set的过程中,我们需要将hour部分进行赋值,赋值我们采用&q ...
- GPUImage每个类的作用
28 #import "GPUImageBrightnessFilter.h" //亮度 29 #import "GPUImageExpos ...
- loj2230 「BJOI2014」大融合
LCT裸题 我LCT学傻了这题明显可以树剖我不会树剖了 本来的siz是Splay上的子树和,并没有什么用. 所以每个点维护虚子树和和子树和 虚子树和即虚边连接的子树和,且只有在access和link操 ...
- jquery选择器:获取父级元素、同级元素、子元素
jQuery的出现给广大开发者提供了不少的方便.从要自己一个一个敲代码,到直接调用方法,无疑大大地提高了网站开发的效率.而在jQuery中有一些方法非常的实用.下面就给大家介绍下jquery选择器:获 ...
- MySQL数据库查询某个库下有几张数据表
如果统计某数据库中存在多少张数据表,使用如下SQL检索语句即可: SELECT COUNT(*) TABLES, table_schema FROM information_schema.TABLES ...