查看原文
其他

说说:为什么新生代要两个Survivor区? 一个不行吗?

聊聊:JVM内存为什么要分成新生代,老年代,永久代。新生代中为什么要分为Eden和Survivor。

思路:

先讲一下JAVA堆,新生代的划分,再谈谈它们之间的转化,

相互之间一些参数的配置(如:–XX:NewRatio,–XX:SurvivorRatio等),

再解释为什么要这样划分,最好加一点自己的理解。

参考答案:

这样划分的目的:是为了使 JVM 能够更好的管理堆内存中的对象,包括内存的分配以及回收。

1)共享内存区划分

  • 共享内存区 = 永久代 (/元空间) + 堆
  • 永久代  =  方法区 + 其他
  • Java堆 =  老年代 + 新生代
  • 新生代 = Eden + S0 + S1

2)一些参数的配置

  • 默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ,可以通过参数 –XX:NewRatio 配置。
  • 默认的,Eden : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定)
  • Survivor区中的对象被复制次数为15   (对应虚拟机参数 -XX:+MaxTenuringThreshold)

3)为什么要分为Eden和Survivor?  为什么要设置两个Survivor区?

  • 如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。

    老年代很快被填满,触发Major GC.

    老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多,

    所以需要分为Eden和Survivor。

  • Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,

    Survivor的预筛选保证,只有经历最大16次Minor GC还能在新生代中存活的对象,才会被送到老年代。

  • 设置两个Survivor区最大的好处就是解决了碎片化,刚刚新建的对象在Eden中,

    经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;

    等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生

说说:为什么新生代内存需要有两个Survivor区?   一个不行吗?

思路:

先讲一下JAVA堆,新生代的划分

再讲讲这样做的宏观目标:  避免内存碎片化

最后讲讲做这种分区架构所面临的场景:大部分的新建对象,都是生命周期很短的, 使用两个Survivor区的架构,取得 内存碎片化  和    执行效率的 最佳平衡。

参考答案:

首先,说明一下默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ,默认的,Eden : from : to = 8 : 1 : 1 ( 可以通过参数 –XX:SurvivorRatio 来设定) 这个  堆内存的结构。


其次,从避免 内存碎片上来说:

在新生代,因为对象的生命周期比较短,为了避免 内存碎片太多, 使用了 标记 复制算法。

在老生代,因为对象的生命周期比较长,为了提升性能,使用了 性能高的 标记清理 或者 标记整理算法。

标记 复制算法,就需要备用空间, 所以两个Survivor ,一个使用,一个备用

从管理的内存大小上来说:

标记 复制算法 ,空间成本高,需要一块额外的内存空间 作为 复制的备用空间,默认情况下,新时代是30%,  用 30%的 10分之一, 也就是 3% 作为 复制的备用空间

备用大部分时候空闲, 3%  的空间是空闲的, 所以内存块不能太大,

CMS是物理分G1是逻辑分代。

而在没有做并发分治模式之前(G1),老生代本身对象生命周期长, 老生代的内存也比价大, 占到60%多,标记 复制算法速度慢, 这么大的内存,不适合使用 标记 复制算法。

不使用 标记 复制算法,也就不需要用 备用空间。

在 做并发分治模式之后(G1),整个内存管理的模式, 已经从大块治理,变成小块治理, G1使用的也是标记复制算法, 本质上,已经可以理解为很多的 轮替备用空间了。如果把那些备用空间理解为 surviver的话,可以理解为,实际上存在N多的surviver区了,只是大家没有用这个名词去命名而已。

最后,总结一下:

因为大部分的新建对象生命周期很短、对象存活率低,用复制算法在回收时的效率会更高,也不会产生内存碎片。

复制算法的代价,  就是需要备用空间,为了不节约过多的内存,就划分了两块雷同大小的内存区域survivor from和survivor to。在每次gc后就会把存活对象给复制到另一个survivor上,而后清空Eden和刚应用过的survivor。

只有在Eden空间快满的时候才会触发 Minor GC 。

而 Eden 空间占新生代的绝大部分,所以 Minor GC 的频率得以降低。

当然,使用两个 Survivor 这种方式我们也付出了一定的代价,如 10% 的空间浪费、复制对象的开销等。

这个标记复制算法,必须付出的代价。

JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代

思路:

先描述一下Java堆内存划分,再解释Minor GC,Major GC,full GC,描述它们之间转化流程。

我的答案:

  • Java堆 = 老年代 + 新生代
  • 新生代 = Eden + S0 + S1
  • 当 Eden 区的空间满了, Java虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对象,则会转移到 Survivor区。
  • 大对象(需要大量连续内存空间的Java对象,如那种很长的字符串)直接进入老年态
  • 如果对象在Eden出生,并经过第一次Minor GC后仍然存活,并且被Survivor容纳的话,年龄设为1,每熬过一次Minor GC,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。即长期存活的对象进入老年态
  • 老年代满了而无法容纳更多的对象,Minor GC 之后通常就会进行Full GC,Full GC 清理整个内存堆 – 包括年轻代和年老代
  • Major GC 发生在老年代的GC清理老年区,经常会伴随至少一次Minor GC,比Minor GC慢10倍以上

聊聊:什么是分代,分代的必要性

Java 虚拟机根据对象存活的周期不同,把堆内存划分为几块,一般分为新生代、老年代和永久代(对 HotSpot 虚拟机而言),这就是

JVM 的内存分代策略。

JDK 1.7 之前,Java 虚拟机将堆内存划分为新生代、老年代和永久代(或者元空间),

永久代是 HotSpot 虚拟机特有的概念(JDK1.8 之后为 metaspace 元空间替代永久代),它采用永久代的方式来实现方法区,其他的虚拟机实现没有这一概念,

而且 HotSpot 也有去永久代的趋势,在 JDK 1.7 中 HotSpot 已经开始了“去永久化”,把原本放在永久代的字符串常量池移出。永久代主要存放常量、类信息、静态变量等数据,与垃圾回收关系不大,新生代和老年代是垃圾回收的主要区域。

堆内存是虚拟机管理的内存中最大的一块,也是垃圾回收最频繁的一块区域,我们程序所有的对象实例都存放在堆内存中。

给堆内存分代 是为了提高对象内存分配和垃圾回收的效率

试想一下,如果堆内存没有区域划分,所有的新创建的对象和生命周期很长的对象放在一起,随着程序的执行,堆内存需要频繁进行垃圾收集,而每次回收都要遍历所有的对象,遍历这些对象所花费的时间代价是巨大的,会严重影响我们的 GC 效率。

有了内存分代,情况就不同了,新创建的对象会在新生代中分配内存,经过多次回收仍然存活下来的对象存放在老年代中,

静态属性、类信息等存放在永久代(或者元空间)中,

新生代中的对象存活时间短,只需要在新生代区域中频繁进行 GC,老年代中对象生命周期长,内存回收的频率相对较低,不需要频繁进行回收,

永久代(或者元空间)中回收效果太差,一般不进行垃圾回收,还可以根据不同年代的特点采用合适的垃圾收集算法。

分代收集大大提升了收集效率,这些都是内存分代带来的好处。

JVM中的永久代中会发生垃圾回收吗

垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。

如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。

这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。


硬核面试题推荐


硬核文章推荐


硬核电子书

本文收录于:《尼恩Java 面试宝典》V17版 


长按二维码,点击“识别图中二维码”即可查看老架构师尼恩个人微信,发暗号 “领电子书” 给尼恩,获取最新PDF。


  • 最新的《尼恩Java面试宝典》

    极致经典,不断升级,目前最新为V17


  • 尼恩Java高并发三部曲

    《Java高并发核心编程-卷1(加强版)》,不断升级

    《Java高并发核心编程-卷2(加强版)》,不断升级

    《Java高并发核心编程-卷3(加强版)》,不断升级


  • 尼恩架构笔记100篇+,不断添加 


继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存