JVM中的新生代和老年代(Eden空间、两个Survior空间)

2023-10-27

现有的主流JVM分别是HotSpot和JRockit,主要研究对象也是这两个。这篇文章里,我们只研究HotSpot,也就是所谓的Sun JVM。目前阶段,Sun的GC方式主要有CMS和G1两种。考虑到效果和实际应用,这里只介绍CMS。CMS,全称Concurrent Mark Sweep,是JDK1.4后期版本开始引入的新GC算法,在JDK5和JDK6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求较高的应用,并且预期这部分应用能够承受垃圾回收线程和应用线程共享处理器资源,且应用中存在比较多的长生命周期的对象的应用。CMS是用于对Tenured Generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少Full GC发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。

JVM在程序运行过程当中,会创建大量的对象,这些对象,大部分是短周期的对象,小部分是长周期的对象,对于短周期的对象,需要频繁地进行垃圾回收以保证无用对象尽早被释放掉,对于长周期对象,则不需要频率垃圾回收以确保无谓地垃圾扫描检测。为解决这种矛盾,Sun JVM的内存管理采用分代的策略。

      1)年轻代(Young Gen):年轻代主要存放新创建的对象,内存大小相对会比较小,垃圾回收会比较频繁。年轻代分成1个Eden Space和2个Suvivor Space(命名为A和B)。当对象在堆创建时,将进入年轻代的Eden Space。垃圾回收器进行垃圾回收时,扫描Eden Space和A Suvivor Space,如果对象仍然存活,则复制到B Suvivor Space,如果B Suvivor Space已经满,则复制到Old Gen。同时,在扫描Suvivor Space时,如果对象已经经过了几次的扫描仍然存活,JVM认为其为一个持久化对象,则将其移到Old Gen。扫描完毕后,JVM将Eden Space和A Suvivor Space清空,然后交换A和B的角色(即下次垃圾回收时会扫描Eden Space和B Suvivor Space。这么做主要是为了减少内存碎片的产生。

我们可以看到:Young Gen垃圾回收时,采用将存活对象复制到到空的Suvivor Space的方式来确保尽量不存在内存碎片,采用空间换时间的方式来加速内存中不再被持有的对象尽快能够得到回收。

      2)年老代(Tenured Gen):年老代主要存放JVM认为生命周期比较长的对象(经过几次的Young Gen的垃圾回收后仍然存在),内存大小相对会比较大,垃圾回收也相对没有那么频繁(譬如可能几个小时一次)。年老代主要采用压缩的方式来避免内存碎片(将存活对象移动到内存片的一边,也就是内存整理)。当然,有些垃圾回收器(譬如CMS垃圾回收器)出于效率的原因,可能会不进行压缩。

      3)持久代(Perm Gen):持久代主要存放类定义、字节码和常量等很少会变更的信息。

              

不过总的说来,Java的GC算法感觉是业界最成熟的,目前很多其他语言或者框架也都支持GC了,但大多数都是只达到Java Serial gc这种层面,甚至分generation都未考虑。JDK7里面针对CMS进行了一种改进,会采用一种G1(Garbage-First Garbage Collection)的算法。实际上Garbage-First paper(PDF) 2004年已经出现。

JVM区域总体分两类,heap区和非heap区。heap区又分:Eden Space(伊甸园)、Survivor Space(幸存者区)、Tenured Gen(老年代-养老区)。 非heap区又分:Code Cache(代码缓存区)、Perm Gen(永久代)、Jvm Stack(java虚拟机栈)、Local Method Statck(本地方法栈)。

HotSpot虚拟机GC算法采用分代收集算法:

1、一个人(对象)出来(new 出来)后会在Eden Space(伊甸园)无忧无虑的生活,直到GC到来打破了他们平静的生活。GC会逐一问清楚每个对象的情况,有没有钱(此对象的引用)啊,因为GC想赚钱呀,有钱的才可以敲诈嘛。然后富人就会进入Survivor Space(幸存者区),穷人的就直接kill掉。

2、并不是进入Survivor Space(幸存者区)后就保证人身是安全的,但至少可以活段时间。GC会定期(可以自定义)会对这些人进行敲诈,亿万富翁每次都给钱,GC很满意,就让其进入了Genured Gen(养老区)。万元户经不住几次敲诈就没钱了,GC看没有啥价值啦,就直接kill掉了。

3、进入到养老区的人基本就可以保证人身安全啦,但是亿万富豪有的也会挥霍成穷光蛋,只要钱没了,GC还是kill掉。

分区的目的:新生区由于对象产生的比较多并且大都是朝生夕灭的,所以直接采用复制算法。而养老区生命力很强,则采用标记-清理算法,针对不同情况使用不同算法。

非heap区域中Perm Gen中放着类、方法的定义,JVM Stack区域放着方法参数、局域变量等的引用,方法执行顺序按照栈的先入后出方式。

简单来讲,JVM的内存回收过程是这样的:

对象在Eden Space创建,当Eden Space满了的时候,gc就把所有在Eden Space中的对象扫描一次,把所有有效的对象复制到第一个Survivor Space,同时把无效的对象所占用的空间释放。当Eden Space再次变满了的时候,就启动移动程序把Eden Space中有效的对象复制到第二个Survivor Space,同时,也将第一个Survivor Space中的有效对象复制到第二个Survivor Space。如果填充到第二个Survivor Space中的有效对象被第一个Survivor Space或Eden Space中的对象引用,那么这些对象就是长期存在的,此时这些对象将被复制到Permanent Generation。若垃圾收集器依据这种小幅度的调整收集不能腾出足够的空间,就会运行Full GC,此时JVM GC停止所有在堆中运行的线程并执行清除动作。

 

1.为什么会有年轻代

我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能。你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用,这样就会对堆的所有区域进行扫描。而我们的很多对象都是朝生夕死的,如果分代的话,我们把新创建的对象放到某一地方,当GC的时候先把这块存“朝生夕死”对象的区域进行回收,这样就会腾出很大的空间出来。

2.年轻代中的GC

HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8:1,为啥默认会是这个比例,接下来我们会聊到。一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。因为年轻代中的对象基本都是朝生夕死的(80%以上),所以在年轻代的垃圾回收算法使用的是复制算法,复制算法的基本思想就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块上面。复制算法不会产生内存碎片。

在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

      

3.一个对象的这一辈子

我是一个普通的Java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定所。直到我18岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加一岁),然后被回收。

4.有关年轻代的JVM参数

1)-XX:NewSize和-XX:MaxNewSize

      用于设置年轻代的大小,建议设为整个堆大小的1/3或者1/4,两个值设为一样大。

2)-XX:SurvivorRatio

      用于设置Eden和其中一个Survivor的比值,这个值也比较重要。

3)-XX:+PrintTenuringDistribution

      这个参数用于显示每次Minor GC时Survivor区中各个年龄段的对象的大小。

4).-XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold

      用于设置晋升到老年代的对象年龄的最小值和最大值,每个对象在坚持过一次Minor GC之后,年龄就加1。

 

本文参考自:

http://lhc1986.iteye.com/blog/1421832

http://www.cnblogs.com/xhr8334/archive/2011/12/01/2270994.html

http://ifeve.com/jvm-yong-generation/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JVM中的新生代和老年代(Eden空间、两个Survior空间) 的相关文章

随机推荐

  • 测试从业1到3年经验,常见软件测试工程师面试题总结

    前言 软件测试工程师 和开发工程师相比起来 虽然前期可能不会太深 但是涉及的面还是比较广的 前期面试实习生或者一年左右的岗位 问的也主要是一些基础性的问题比较多 涉及的知识主要有MySQL数据库的使用 Linux操作系统的使用 软件测试框架
  • SpringMVC文件的上传下载&JRebel的使用

    目录 前言 一 JRebel的使用 1 IDea内安装插件 2 激活 3 离线使用 使用JRebel的优势 二 文件上传与下载 1 导入pom依赖 2 配置文件上传解析器 3 数据表 4 配置文件 5 前端jsp页面 6 controlle
  • 【多目标跟踪MOT学习笔记】字节跳动ByteTrack论文研究(一):BYTE策略

    文章目录 前言 一 是什么ByteTrack 二 BYTE 1 BYTE method 概览 2 First Association 关联1 3 Second Association 关联2 4 Post Processing 后处理 4
  • 涅槃重生,BitKeep如何闯出千万用户新起点

    在全球 BitKeep钱包现在已经有超过千万用户在使用 当我得知这个数据的时候 有些惊讶 也有点意料之中 关注BitKeep这几年 真心看得出这家公司的发展之迅速 还记得2018年他们推出第一个版本时 小而美 简洁顺手 他们大胆且略显理想主
  • [非线性控制理论]4_反馈线性化_反步法

    非线性控制理论 1 Lyapunov直接方法 非线性控制理论 2 不变性原理 非线性控制理论 3 基础反馈稳定控制器设计 非线性控制理论 4 反馈线性化 反步法 非线性控制理论 5 自适应控制器 Adaptive controller 非线
  • 【操作系统 · 线程】介绍、分类、多线程

    线程 介绍 分类 多线程 一 介绍 1 进程与线程 2 多线程 3 线程的功能 二 线程分类 1 用户级线程 2 内核级线程 3 其他方案 三 多核 多线程 一 介绍 进程中有两个重要概念 资源所有权 执行 因这一区别 许多操作系统中出现了
  • ueditor1.5 新版ueditor设置字体大小文件所在位置

    ueditor src plugins font js文件 将想添加的字体大小设置即可 fontsize 10 11 12 14 16 18 20 24 36 72
  • 【HBZ分享】java之二叉堆排序实战代码

    废话不多说 直接上代码 注释都在代码中 利用大顶堆排序 最终数组从小到大 复制即用无需导包 package 大顶堆 import java lang reflect Array import java util Arrays public
  • 30天自制操作系统学习-第1天

    第一天 1 批处理文件 直接由DOS命令行解释执行的文件 通常后缀名为 bat或 cmd 2 镜像文件 img后缀的文件 可用于制作操作系统文件 一个3 5英寸的软盘容量为1440k 3 nask 作者自己制作的汇编代码编译器 代码与nas
  • Adobe Creative Suite 5.5 简体中文版

    http www itopdog cn graphic image web design software adobe creative suite html Adobe Creative Suite 5 5 简介 Adobe Creati
  • xml和javaBean实现互转

    最近遇到了调用接口需要xml报文传递 用传统最简单的方式就是我们string手动拼接报文传递 这样调用问题解决了 返回的数据问题没有得到解决 因为返回的也是xml报文 需要对其做一些转换操作 既然转换 直接在传递时通过简单的方式将报文序列化
  • Python 日志管理模块logging

    参考 link https www cnblogs com nancyzhu p 8551506 html 日志 日志是跟踪软件运行时所发生的事件的一种方法 软件开发者在代码中调用日志函数 表明发生了特定的事件 事件由描述性消息描述 该描述
  • ORA-12505: TNS: 监听程序当前无法识别连接描述符中所给出的SID等错误解决方法

    程序连接orarle报ORA 12505错误 一 异常 ORA 12505 TNS listener does not currently know of SID given in connect descriptor The Connec
  • VTK_python入门

    tk基本介绍 VTK 库的框架结构 vtkObject gt vtkSource gt vtkFilter gt vtkMapper gt vtkActor gt vtkRenderer 对象 介绍 vtkObject vtk库的基类 vt
  • 人脸对齐:使用 PyTorch 检测人脸特征点(附Wget下载方法)

    开发环境 作者 嘟粥yyds 时间 2023年8月12日 集成开发工具 Google Colab 集成开发环境 Python 3 10 6 第三方库 torch torchvision cv2 xml os math matplotlib
  • CVPR 2023

    点击下方卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 点击进入 自动驾驶之心 语义分割 技术交流群 后台回复 分割综述 获取语义分割 实例分割 全景分割 弱监督分割等超全学习资料 论文思路 多模态融合可以使语义分割更加鲁棒
  • Scala 之 高阶函数

    函数式编程 Scala函数式编程是scala的重中之重 老师多次强调它的重要性 spark当中的计算都是用scala函数式编程来做 高级函数也是其独特的一个特性 并且spark基于集合 这样可以使scala发挥其对于集合计算的强大功能 首先
  • Jenkins拉取Gitee代码问题笔记记录

    最近在自学自动化部署 用到了jenkins但是一直拉取gitee上的代码失败 尝试了网上各自配置项目的方法都不行 报错如下 由用户 c 启动 构建中 在工作空间 C Users Administrator jenkins workspace
  • uni-app开发微信小程序,IOS苹果手机上时间格式化错误显示Invalid Date问题解决方案

    1 问题描述 只在真机IOS上面才会出现 小程序模拟器上的ios是不会出现的 原因是因为时间格式只要带有 符号就会 但有个ios机型却不会出错 我用苹果11测试会出现Invalid Date 有几种情况 例如 1 new Date 2023
  • JVM中的新生代和老年代(Eden空间、两个Survior空间)

    现有的主流JVM分别是HotSpot和JRockit 主要研究对象也是这两个 这篇文章里 我们只研究HotSpot 也就是所谓的Sun JVM 目前阶段 Sun的GC方式主要有CMS和G1两种 考虑到效果和实际应用 这里只介绍CMS CMS