美文网首页
JVM 新生代内存结构形成的由来

JVM 新生代内存结构形成的由来

作者: 爱蛇 | 来源:发表于2019-03-08 21:45 被阅读0次

    问题

    1. 新生代(Young Generation) 里为什么要分成以下内存块?
      Eden + Survivor 0 + Survivor 1

    2. 为什么这些内存块默认的比例是8:1:1?

    以下要说的内容是从《深入理解JAVA虚拟机》书中总结出来的。

    新生代内存结构演进:

    1. 单块内存

    如果jvm 只分配单一块内存进行存储所有新创建的对象,那么JVM可以怎么样回收内存呢? 请参考以下内存分配情况:


    单一块内存回收(即标记-清除算法)

    在回收内存时,先把可回收的对象进行标记(如图中的对象2),
    然后清除这些被标记的对象。

    这种过程叫【标记-清除】算法,但有两个缺点:

    1. 标记过程 和 清除过程的效率都不高;
    2. 会造成很多内存碎片,如图对象2被清除后,留下来的这一块内存就属于内存碎片,后续jvm应该是不会使用,因为如果要使用还得要计算这块内存碎片的范围,这么一来效率就更低。

    2. 分成两块1:1的内存

    基于第一点的情况,把内存分成两块比例一样的内存。每次回收内存时,将存活的对象直接复制到另外一块内存中,然后清除原来内存块。

    两块比例相同内存的回收(即复制算法)

    这种过程叫【复制】算法,但也有缺点:

    1. 运行时只使用50%的内存进行分配对象,剩余50%的内存空间是被浪费的;
    2. 如果每次GC时只扫描第一块内存,那么第二块内存上的对象岂不是长期存活而不能被释放?所以这里缺少了一个“再次检查是否存活”的机制。

    3. 分成 8:1:1 三块内存

    基于第2点,实际情况下,98%的对象都是存活率为0,所以可以将运行时的内存(即第2点中的第一块内存)所占用的比例调整大一点。并且增加“再次检查对象是否存活”的机制,分配成8:1:1 三块内存,分别为:
    eden , survivor A , survivor B

    并将eden 和 survivor A 标记成运行时内存,将survivor B 标记成保留内存(用于复制的保留内存)。

    每次GC时,都从将eden 与其中一块属于“运行时”的内存survivor A所存活对象复制到 另外一块用于复制的内存 survivorB,并标记这些对象的age 递增1
    ,然后将原来内存 eden 和 survivor A 内存的对象全部清除,
    最后将survivor A 跟 survivor B(survivorB存在存活的对象) 角色交换。
    那么下一次GC时,将扫描 eden + survivor B 内存的存活对象,而survivor A内存作为复制目标内存块。
    存活对象只要age 达到某一个数值(默认jvm配置是15)则直接将该对象迁移到老年代中。这样做的目的是为了防止其中一块survivor被挤爆,增加了一个迁移到老年代的机制。

    关于存活对象的age 设置:

    -XX:MaxTenuringThreshold=15
    

    补充: 在以上推算过程,是基于每次GC时存活率对象都小于survivor区也就是10%。
    但实际情况有可能GC时,存活的对象大小可能比survivor 大,那么这个时候就直接复制到用于担保机制的老年代中。

    以上纯属个人理解,有说不对请上砖。

    相关文章

      网友评论

          本文标题:JVM 新生代内存结构形成的由来

          本文链接:https://www.haomeiwen.com/subject/gzmdpqtx.html