JVM内存结构--新生代及新生代里的两个Survivor区(下一轮S0与S1交换角色,如此循环往复)、常见调优参数

JVM虚拟机(四)年轻代中的 S0区、S1区和 from区、to区有什么区别? 阅读详情

 

2017年06月13日 15:10:12 含笑半步癫123 阅读数:4003

转自http://www.cnblogs.com/duanxz/p/6076662.html

 

一、为什么会有年轻代

 

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

二.年轻代中的GC

  新生代大小(PSYoungGen total 9216K)=eden大小(eden space 8192K)+1个survivor大小(from space 1024K)

  HotSpot JVM把年轻代分为了三部分:1个Eden区和2个Survivor区(分别叫from和to)。默认比例为8(Eden):1(一个survivor),为啥默认会是这个比例,接下来我们会聊到。一般情况下,新创建的对象都会被分配到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”区被填满之后,会将所有对象移动到年老代中。

三、一个对象的这一辈子

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

四、为什么要有Survivor区

先不去想为什么有两个Survivor区,第一个问题是,设置Survivor区的意义在哪里? 

 

如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。你也许会问,执行时间长有什么坏处?频发的Full GC消耗的时间是非常可观的,这一点会影响大型程序的执行和响应速度,更不要说某些连接会因为超时发生连接错误了。

好,那我们来想想在没有Survivor的情况下,有没有什么解决办法,可以避免上述情况:

方案优点缺点
增加老年代空间更多存活对象才能填满老年代。降低Full GC频率随着老年代空间加大,一旦发生Full GC,执行所需要的时间更长
减少老年代空间Full GC所需时间减少老年代很快被存活对象填满,Full GC频率增加

显而易见,没有Survivor的话,上述两种解决方案都不能从根本上解决问题。

我们可以得到第一条结论:Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。

五、为什么要设置两个Survivor区

设置两个Survivor区最大的好处就是解决了碎片化,下面我们来分析一下。

为什么一个Survivor区不行?第一部分中,我们知道了必须设置Survivor区。假设现在只有一个survivor区,我们来模拟一下流程: 
刚刚新建的对象在Eden中,一旦Eden满了,触发一次Minor GC,Eden中的存活对象就会被移动到Survivor区。这样继续循环下去,下一次Eden满了的时候,问题来了,此时进行Minor GC,Eden和Survivor各有一些存活对象,如果此时把Eden区的存活对象硬放到Survivor区,很明显这两部分对象所占有的内存是不连续的,也就导致了内存碎片化。 
我绘制了一幅图来表明这个过程。其中色块代表对象,白色框分别代表Eden区(大)和Survivor区(小)。Eden区理所当然大一些,否则新建对象很快就导致Eden区满,进而触发Minor GC,有悖于初衷。 

 

碎片化带来的风险是极大的,严重影响Java程序的性能。堆空间被散布的对象占据不连续的内存,最直接的结果就是,堆中没有足够大的连续内存空间,接下去如果程序需要给一个内存需求很大的对象分配内存。。。画面太美不敢看。。。这就好比我们爬山的时候,背包里所有东西紧挨着放,最后就可能省出一块完整的空间放相机。如果每件行李之间隔一点空隙乱放,很可能最后就要一路把相机挂在脖子上了。

那么,顺理成章的,应该建立两块Survivor区,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生)。S0和Eden被清空,然后下一轮S0与S1交换角色,如此循环往复。如果对象的复制次数达到16次,该对象就会被送到老年代中。下图中每部分的意义和上一张图一样,就不加注释了。 

上述机制最大的好处就是,整个过程中,永远有一个survivor space是空的,另一个非空的survivor space无碎片。

那么,Survivor为什么不分更多块呢?比方说分成三个、四个、五个?显然,如果Survivor区再细分下去,每一块的空间就会比较小,很容易导致Survivor区满,因此,我认为两块Survivor区是经过权衡之后的最佳方案。

参考:
http://blog.youkuaiyun.com/antony9118/article/details/51425581

http://stackoverflow.com/questions/21476348/java-gc-why-two-survivor-spaces

六、有关年轻代的JVM参数

1)-XX:NewSize和-XX:MaxNewSize(jdk1.3or1.4)

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

2)-Xmn(jdk1.4or lator)

用于设置年轻代大小。例如:-Xmn10m,设置新生代大小为10m。此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是(eden+1 survivor space)不同的。

3)-XX:SurvivorRatio

用于设置Eden和其中一个Survivor的比值,默认比例为8(Eden):1(一个survivor),这个值也比较重要。

例如:-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6。

例子:-XX:SurvivorRatio=8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10。

复制代码

package com.jvm.study.part3;

import java.util.concurrent.TimeUnit;

public class GCTest {

    private static final int _1MB = 1024 * 1024;
    
    /**
     * @VM args:-verbose:gc -Xms20m -Xmx20m -Xmn10m -XX:SurvivorRatio=8
     */
    public static void testAllocation() {
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[2 * _1MB];
        System.out.println("1");
        allocation2 = new byte[2 * _1MB];
        System.out.println("2");
        allocation3 = new byte[2 * _1MB];
        System.out.println("3");
        allocation4 = new byte[2 * _1MB];
        System.out.println("4");
        
    }
    public static void main(String[] args) throws InterruptedException {
        TimeUnit.SECONDS.sleep(30);
        testAllocation();
    }

}

复制代码

结果:

复制代码

1
2
3
[GC (Allocation Failure) [PSYoungGen: 7136K->632K(9216K)] 7136K->6784K(19456K), 0.0084250 secs] [Times: user=0.01 sys=0.01, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 632K->0K(9216K)] [ParOldGen: 6152K->6635K(10240K)] 6784K->6635K(19456K), [Metaspace: 2562K->2562K(1056768K)], 0.0092126 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
4
Heap
 PSYoungGen      total 9216K, used 2290K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 27% used [0x00000000ff600000,0x00000000ff83c960,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6635K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 64% used [0x00000000fec00000,0x00000000ff27afa8,0x00000000ff600000)
 Metaspace       used 2569K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 277K, capacity 386K, committed 512K, reserved 1048576K

复制代码

 

结果分析:

1、-Xmn=10m,但实际的新生代大小(PSYoungGen total 9216K)=eden大小(eden space 8192K)+1个survivor大小(from space 1024K)

4)-XX:+PrintTenuringDistribution

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


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

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

JVM内存模型和性能调优:JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区?- 第18篇 前言 Java为什么要设计Survivor,而且还要设计两个呐? 一、为什么要有Survivor区 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时... 阅读详情

相关推荐

Unity游戏开发实战:用柏林噪声打造3D随机地形(附完整C#代码)

本文详细介绍了如何在Unity游戏开发中使用柏林噪声算法生成3D随机地形,包含完整的C#代码实现。从基础柏林噪声原理到高级参数控制,再到性能优化和常见问题解决,帮助开发者掌握程序化地形生成技术,打造丰富多变的游戏世界。

weixin_29281941的博客 102

JVM体系结构之六:堆Heap之2:新生代及新生代里的两个Survivor区(下一轮S0与S1交换角色,如此循环往复)、常见调优参数...

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

weixin_34004576的博客 796

Workbench下列车转向架随机振动疲劳分析

结果中添加功率谱响应工具(Response PSD Tool),可以查看几何体以及远程点上的功率谱密度,如下图11所示,这里查看几何体上某一硬点的加速度功率谱密度响应曲线,如下图12所示。结果中添加疲劳工具(Fatigue Tool),查看列车转向架的疲劳寿命情况,这里采用窄带的寿命假设理论,曝光时间为1s指明计算出的疲劳寿命的基本单位是秒,寿命结果如下图14所示,可以看到最大寿命为1e35s,最小寿命为2.3542e18s,注意单位制,可再次基础上将其转换为小时或天。频域上的统计计算,软件很快计算完成。

ansysxuexizhe的博客 2605

jvm 调优实战之 堆内存PSYoungGen 年轻代 大对象,eden ,SurvvorFrom ,SurvvorTo 介绍,minorGC 流程详解以及验证demo和相关jvm配置参数

jvm调优基础之 堆内存PSYoungGen 年轻代 大对象,eden ,SurvvorFrom ,SurvvorTo 介绍,minorGC 流程详解以及验证demo和相关jvm配置参数 -XX:NewRatio=2 -Xms100M -Xmx100M -XX:+PrintGCDetails -XX:PretenureSizeThreshold=1048576 -XX:SurvivorRatio=8 -XX:+UseSerialGC

峡谷电光马仔的博客 3609

Python自动化测试全套教程-第一天(python、pycharm开发环境的安装与配置(图文超级详细);附安装包)

本文介绍了Python开发环境的完整安装配置流程。主要内容包括:1) Python解释器的下载安装与版本检测方法;2) PyCharm IDE的下载安装步骤,包括专业版和社区版的选择;3) PyCharm的基础配置和项目创建方法;4) 开发环境的基本构造说明。文章提供了两种获取安装包的方式(官网下载和文章附件),并详细说明了解释器卸载、安装过程中的注意事项,以及如何验证环境配置成功。特别强调了PyCharm安装时的路径选择和虚拟环境的创建方法,为Python初学者提供了完整的开发环境搭建指南。

kiwi_king的博客 2036

Windows如何使用Anaconda 3进行keras环境的配置

** Windows如何使用Anaconda 3进行keras环境的配置 搭建Keras环境* Anaconda3如何安装keras,主要包括下面三步: 1.安装mingw libpython 2.安装theano 3.安装keras 若你还没有按装anaconda,赶紧下载安装吧! 下载途径有两个 (1)Anaconda版本为Anaconda 4.4.0,对应的python版本为3.6,附上An...

Lance_liangliang的博客 1602

java psyounggen,【java学习】GC排查-Go语言中文社区

1,GC log通过配置可以查看gc日志。tomcat.gc.logMajor GC2019-10-12T18:20:08.224+0800: 2.287: [GC (Allocation Failure) [PSYoungGen: 524800K->29911K(611840K)] 524800K->30015K(2010112K), 0.0896057 secs] [Times: ...

weixin_39812186的博客 521

Ambari 3.0.0 + BigTop 3.3.0 源码编译与集群部署指南(Kylin V10 / aarch64)

仅仅是针对“应用商店目录(Applications Catalog)”的一个外围附属子模块(它不是 YARN 监控大盘,不影响 YARN UI 网页的主体使用),我们可以采用。自带的 Node 二进制是 x86_64 版本,在 ARM64(aarch64)容器上无法执行(Exit value: 126)。:Ambari Server/Agent 使用 JDK 17,BigTop 大数据组件(Hadoop/HBase/Spark 等)使用 JDK 8。,源码中包含 x86 特定的原生二进制文件。

amumu1992的博客 492

四、垃圾回收(二)

Eden区所有的存活对象都存放到To区,From区的对象根据自身的年龄值来决定去向(年龄达到一定的值后对象直接移动到老年代中,没有达到阀值则被复制到To区),有个疑问,From区的对象是否会有没用的对象?没有survivor区,则eden区每次minor后都会把存活的对象存到老年代中,那么老年代很快就会被填满,从而触发FullGC,老年代的空间要比年轻代打,直到触发过程中,To区被填满,会把对象都移动到老年代中,至此年轻代中都为空了,此时可能会触发FullGC,也可能不会,看老年代的内存大小了。

郭鹏恩欢迎您 188

Webots+UR机械臂仿真全流程:手把手教你用Python实现Pick-and-Place轨迹规划

本文详细介绍了使用Webots和Python实现UR六自由度机械臂的Pick-and-Place轨迹规划全流程。从环境搭建、运动学正逆解计算到轨迹规划实战技巧,涵盖工业场景中的关节补偿、末端校准等实际问题解决方案,帮助开发者快速掌握机械臂精准控制技术。

weixin_29083649的博客 284

LeRobot 入门教程(二)强化学习训练及 SmolVLA 模型微调

本文介绍了LeRobot框架中基于人类在环的样本高效强化学习(HIL-SERL)工作流,包含真实机器人训练和模拟环境训练两大模块。在真实机器人部分,详细说明了从配置设置、工作空间边界确定、演示数据收集、奖励分类器训练到演员-学习者架构部署的全流程,并强调了人类干预的关键作用。同时介绍了适用于模拟训练的gym_hil环境及其配置使用方法。最后,文章提供了微调SmolVLA基础模型的指南,包括数据集收集、微调步骤和模型评估方法。该工作流实现了人机协作的高效强化学习,适用于各类机器人操作任务。

2506_90492529的博客 3900

java eden s0 s1_JVM内存结构--新生代及新生代里的两个Survivor区(下一轮S0与S1交换角色,如此循环往复)、常见调优参数...

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

weixin_30599521的博客 594

Qt for WebAssembly环境搭建

一、前言 二、Ubuntu 1、在线安装Qt15 在线安装下载器:https://download.qt.io/official_releases/online_installers/ 安装时记得勾选WebAssembly,如下: 2、安装依赖 # Install Python sudo apt-get install python2.7 # Install CMake (optional, only needed for tests and building Binaryen) sudo apt

贝勒里恩的博客 3670

JVM内存结构--新生代及新生代里的两个Survivor区(下一轮S0与S1交换角色,如此循环往复)、常见调优参数...

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

a8605428的博客 244

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

为什么JVM中的新生代要有两个Survivor区?

转自https://blog.youkuaiyun.com/antony9118/article/details/51425581那么,在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区?1 为什么要有Survivor区先不去想为什么有两个Survivor区,第一个问题是,设置Survivor区的意义在哪里? 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象

towads的博客 1万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

新生代内存需要有两个Survivor区 S0、S1

在我的上一篇博客中,介绍了JVM堆内存的结构以及在堆中进行的GC机制,链接是浅谈JAVA GC机制与性能优化 那么,在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区? 1 为什么要有Survivor区 先不去想为什么有两个Survivor区,第一个问题是,设置Survivor区的意义在哪里? 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也

szw906689771的博客 1788

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

为什么新生代内存需要有两个Survivor区

堆内存分为新生代和老年代,其中新生代分为Eden和两块Survivor,本文探讨了为什么要设置两块Survivor区

橙子wj的博客 3万+

【JVM】survivor区的解释

那么,在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区? 1 为什么要有Survivor区 先不去想为什么有两个Survivor区,第一个问题是,设置Survivor区的意义在哪里? 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC

JavaPub 3685

在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区?

在JVM的新生代内存中,为什么除了Eden区,还要设置两个Survivor区? 1 为什么要有Survivor区 先不去想为什么有两个Survivor区,第一个问题是,设置Survivor区的意义在哪里? 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。 老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。你

bishe_teacher的博客 601
上一篇: 批量执行hbase shell 命令 major_compact('t_abc')
下一篇: 一个字母占几个字节
王树民
博客等级 码龄10年 912粉丝 560原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值