Java垃圾回收精粹 — Part2
Java垃圾回收精粹分4个部分,本篇是第2部分。在第2部分里介绍了Hotspot中的堆结构、对象分配以及次要回收。
Hotspot中的堆结构
理解不同的收集器的工作方式,是探讨Java堆结构如何支持分代机制的最好的方式。
伊甸区(Eden)的大部分对象都是刚刚被分配的。幸存区(survivor)用来临时存储那些从伊甸区里幸存下来的对象。当我们讨论完次要回收(minor collections)后将描述幸存区的用途。伊甸区和幸存区统称为“年轻代”或 “新生代”存活足够久的对象,将最终移到年老(tenured )区里。
永久代在运行时存储永不销毁对象的区域,比如像类和静态字符串。不幸的是,在许多应用程序中,持续运行的类加载这一常见用途背后隐藏了一个激进的假设:即类是不会被销毁。在Java 7中,本地化的String会从永久代(perm gen)代移动到年老区。从Java 8开始,HotSpot虚拟机中删除了“永久代”。这是题外话,不再过多探讨。大部分其他的商业收集器不使用一个单独的永久代,而是往往把所有长期存活的对象放到年老代里面。
注意:虚拟空间允许收集器调整区块大小,以满足延迟和吞吐量的要求。收集器对每一次的收集做统计,并调整相应区的大小以达设定的目标。
对象分配
为了避免竞争,每个线程都指派了一个“线程本地分配缓冲区”(Thread Local Allocation Buffer,缩写TLAB)用于分配对象。TLAB通过避开单个内存资源竞争问题的方式,使得对象分配的规模可以等同于线程的数量。用TLAB分配对象是一个廉价的操作,只是为对象的大小分配一个指针,在大部分平台上需要约10个指令。Java堆内存的分配比C运行时使用malloc ()分配内存更加廉价。
注意:有鉴于个别对象分配是很廉价的,次要回收(minor collection)发生率必须与对象分配的速率成正比。
当一个TLAB被耗尽后,线程可以简单地从伊甸区请求一个新的。当伊甸区用完后,开始一次次要回收。
大对象(-XX:PretenureSizeThreshold=<n>)在年轻代的分配可能失败,因此必须分配在老年代,比如:大数组。如果Threshold(阈值)的设置低于TLAB大小,那么遇到合适TLAB的对象就不会创建在年老代。G1的新收集器在处理大对象的时候有所不同,将在后面部分单独讨论。
次要回收(Minor Collections )
当伊甸区填满时会触发次要回收。这一过程将所有新生代里存活的对象适当的复制到幸存区(survivor space)和年老区(tenured space)。复制到年老区通常称为晋升(promotion)或者老年化(tenuring)。晋升发生在那些对象足够老(– XX:MaxTenuringThreshold=<n>)或者幸存空间溢出时。
存活对象是指那些应用程序可以访问到的对象;任何不能访问的其他对象,都可以认为是死对象。在次要回收中,存活对象的复制从GC根开始,逐个复制这些可访问的对象到幸存区最后完成。
GC根通常包括应用程序的引用、JVM内部的静态字段的引用以及线程堆栈帧的引用,所有这些构成了应用程序的可访问对象图。
在分代回收中,新生代可访问对象图中的GC根还包括年老代对新生代的任何引用。这些引用也必须进行处理,以确保在新生代里面所有可访问对象在次要回收后仍然是存活的。识别这些跨代引用使用了“卡片表(card table)”。Hotspot 的卡片表是一个bytes数组,其中每个字节用于跟踪相对应年老代里的512byte区域中可能存在的跨代引用。因为引用被存储在堆里,“存储屏障(store barrier)”代码将标记卡片来表示在其相应的512个字节的堆区域,可能存在从年老代到新生代的一个潜在引用。 在回收时卡片表被用于扫描跨代引用,这会为新生代有效地添加一个GC根。因此在次要回收中,一个重要的固定成本是与年老代大小成正比。
在Hotspot中,新生代有两个幸存区:交替的扮演“到达空间(to-space)”和“出发空间(from-space)”的角色。在次要回收刚开始的时候,到达空间的幸存区总是空的,扮演着次要回收中的的目标复制区域的角色。上个次要回收的目标幸存区是这次出发空间的幸存区的一部分。类似的还有伊甸区,里面的存活对象都需要复制。
次要回收的主要消耗在复制对象到幸存区和年老区上。非幸存对象在次要回收中不会被处理。次要回收的工作量直接与存活对象的数量相关,而与新生代的大小无关。Eden的大小每增加一倍,次要回收的总时间可以减少几乎一半。这样可以在内存和吞吐量中找到平衡。Eden的大小翻倍会增加每一次GC周期所占的回收时间。但是如果需要晋升的对象数量和年老代的大小是固定的,那么额外增加的时间会相对较少。
注意:在Hotspot中次要收集是个全局暂停事件。随着我们的堆越来越大,存活对象越来越多,这会变成一个很大的问题。我们已经开始看到在新生代中使用并发收集以减少暂停时间的需要。
主要回收(Major Collections)
“主要回收”是指在旧生代(old gen)上的垃圾收集,以便对象可以从年轻代晋升上来。在大多数应用程序中,绝大部分的程序状态都会在老年代里结束。最多种类的GC算法也是用在老年代上。有一些是整个空间填满时开始压缩,另一些是回收与应用程序并行以防整个空间被填满。
老年代的收集器会尝试预测什么时候需要收集,以避免年轻代的晋升失败。收集器跟踪设置在老年代上的阈值,达到法制就会进行一次回收。如果这个阈值达不到晋升条件,则触发一次“FullGC”。一次FullGC包括晋升所有年轻代中的被收集器追踪的对象,并压缩老年代。晋升失败是个非常昂贵的操作,因为这个周期里所有的状态和晋升对象都必须松开以触发FullGC。
注意:为了避免晋升失败,你需要调整你的填充空间,为老年代提供可以存放晋升后的对象(XX:PromotedPadding=<n>)。
注意:当触发FullGC时,堆可能需要增长。要避免在FullGC时调整堆大小,可以将 –Xms 和 –Xmx 设为相同的值,
与FullGC相比,一次年老代的压缩可能会是应用程序经历最久的全局暂停。压缩的时间和在年老区(tenured space)中存活对象的数量增长呈线性关系。
有时候,年老区的填充率可以通过增大幸存区(survivor spaces)大小和延长晋升到年老区前对象的存活寿命来减少。然而, 增大幸存区大小和延长晋升之前对象在次要收集 (–XX:MaxTenuringThreshold=<n>)中的存活寿命,也会增加次要回收成本和暂停时间,这样的话,幸存区之间的复制成本就会增加。
Java垃圾回收精粹 — Part2的更多相关文章
- Java垃圾回收精粹 — Part4
Java垃圾回收精粹分4个部分,本篇是第4部分.在第4部分里介绍了G1收集器.其他并发收集器以及垃圾收集监控和调优. Garbage First (G1) 收集器 G1 (-XX:+UseG1GC)收 ...
- Java垃圾回收精粹 — Part3
Java垃圾回收精粹分4个部分,本篇是第3部分.在第3部分里介绍了串行收集器.并行收集器以及并发标记清理收集器(CMS). 串行收集器(Serial Collector) 串行收集器是最简单的收集器, ...
- Java垃圾回收精粹 — Part1
Java垃圾回收精粹分4个部分,本篇是第1部分.在第1部分里介绍了权衡点.对象生命周期以及全局暂停事件. 串行.并行.并发.CMS.G1.年轻代(Young Gen).新生代(New Gen).旧生代 ...
- 【转载】Java垃圾回收机制
原文地址:http://www.importnew.com/19085.html Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联 ...
- 【转】深入理解 Java 垃圾回收机制
深入理解 Java 垃圾回收机制 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
- 深入理解java垃圾回收机制
深入理解java垃圾回收机制---- 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...
- Java GC系列(2):Java垃圾回收是如何工作的?
本文由 ImportNew - 伍翀 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 本教程是为了理解基本的Java垃圾回收以及它是如何 ...
- Java GC系列(1):Java垃圾回收简介
本文由 ImportNew - 好好先生 翻译自 javapapers. Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Ja ...
- Java垃圾回收介绍(译)
在Java中,对象内存空间的分配与回收是由JVM中的垃圾回收进程自动完成的.与C语言不同的是,在Java中开发者不需要专门为垃圾回收写代码.这是使Java流行的众多特征之一,也帮助了程序员写出了更好的 ...
随机推荐
- Linux 基础——常用的Linux网络命令
一.学Linux网络命令有什么好处 网络的出现,我们的生活更方便了,处理事情的效率也越来越高,也可以看到全世界文化的差异.同时我们接受新事物的信息越来越来强,新事物的信息也越来越来多.网络对于我们尔等 ...
- Hilite代码高亮工具
在用<有道云笔记>等软件时候,软件自身不提供代码高亮功能,对于需要记录code的学习笔记,视觉效果丢失. 有很多在线工具能用来代码高亮,比如oschina就有代码高亮页面用于着色. 但是我 ...
- 2.4G无线模块NRF2401
RF24L01+,是工作在2.4~2.5GHz 频段的,具备自动重发功能,6 个数据传输通道,最大无线传输速率为2Mbits.MCU 可与该芯片通过SPI 接口访问芯片的寄存器进行配置,达到控制模块. ...
- html5本次存储几种方式
一.cookies 大家都懂的,不必多说 二.sessionStorage/localStorage HTML5 LocalStorage 本地存储 说到本地存储,这玩意真是历尽千辛万苦才走到HTML ...
- 【51nod】1594 Gcd and Phi
题解 跟随小迪学姐的步伐,学习一下数论 小迪学姐太巨了! 这道题的式子很好推嘛 \(\sum_{i = 1}^{n} \sum_{j = 1}^{n} \sum_{d|\phi(i),\phi(j)} ...
- Vsftpd支持SSL加密传输
ftp传输数据是明文,弄个抓包软件就可以通过数据包来分析到账号和密码,为了搭建一个安全性比较高ftp,可以结合SSL来解决问题 SSL(Secure Socket Layer)工作于传输层和应用程 ...
- 洛谷P1486 [NOI2004]郁闷的出纳员 [STL,平衡树]
题目传送门 郁闷的出纳员 题目描述 OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反 ...
- properties文件乱码问题 eclipse
java最常用的开发工具eclipse里面的properties配置文件里面打开中文是乱码的,解决方式很简单. 将default encoding 设置为utf-8即可. 效果: 漂亮!!!
- java.lang.TypeNotPresentException: Type org.eclipse.jetty.maven.plugin.JettyRunMojo not present的原因
原因 :我的JDK版本不支持当前Jetty版本. 解决:将jetty版本换成较低版本的就可以,这个是我之前的我的jdk是1.7.7的 <groupId>org.eclipse.jetty& ...
- JSP与Servlet传值及对比
JSP是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达. JSP编译后是”类servlet”. Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在 ...