本文源自Recently祝祝,创自Recently祝祝。转载请标注出处。

此解决方式在企业中有所应用,适合Java初级开发学习,参考。

本文字数与行数,耐性阅读必有收获。

堆内存结构

让人一看就懂的JVM之年轻代(Young)、老年代(Old)

堆的内存结构:

  • 年青代
    • Eden区域:新建目标所在的区域
    • Survivor0区:当Eden区域满的时分,进行一次Minor GC,存活目标进入Survivor0区,Eden区域存活目标会与Survivor区域合并
    • Survivor1区:当Survivor0区满了,也会进行一次Minor GC ,存活目标复制进Survivor1区。Survivor1会依据目标年纪判断进入老时代还是继续复制到Survivor另一个区域里面。
  • 老时代
    • 老时代:当Eden区域创建的目标,MinorGC之后超越Survivor百分之五十内存的目标会进入老时代。通过15次Minor GC还存活的目标会进入老时代。
  • 元空间:在1.8之后永久代被元空间替代。存取数据更灵敏。
    • 存储元数据:例如:类名、访问修饰符、方法信息、字段信息等数据信息
    • 元空间存储的便是运行时常量池的数据

为什么堆内存要分年青代和老时代?

让人一看就懂的JVM之年轻代(Young)、老年代(Old)

  • 主要原因–》分代搜集理论:将简单收回目标放入年青代,不简单收回目标寄存进入老时代。为了提高废物收回的功率,削减废物收回的频次和时刻。

  • 依据分代搜集理论,分为强分代假说、弱分代假说。将简单消亡的目标寄存到弱分代中,存活时刻长的寄存到强分代中。为了功率更高的进行废物收回,依据生命周期的长短分为年青代和老时代两类。

  • 年青代

    • 年青代生命周期短,更简单被进行废物收回,需要更屡次的进行废物收回。
    • 年青代分为三个区Eden区、Surivivor0区、Survivor1区。新创建的目标会先进入Eden区,当Eden区满了之后,会进行一次废物收回Minor GC,将存活下来的目标复制到Survivor0区,当Survivor0区满了,再次进行废物收回,存活下来的复制进入Survivor1区。Survivor1区满了,又复制进Survivor0区,循环往复。每复制进入Survivor区中年纪+1,当年纪达到15的时分就会被寄存到老时代。
  • 老时代

    • 生命周期长,更少的目标需要被收回,不需要频频的进行废物收回。
    • 目标从年青代进入老时代,当老时代满了的时分,会进行一次Major GC ,全局废物收回。
  • 老时代的Major GC与年青代的MinorGC 比较不需要那么频频并且但是耗时会更长,依据以上特点将内存区域分为老时代和年青代。

年青代进入老时代的整个过程

  1. 新目标请求–》

  2. 进入Eden区,判断内存大小是否能够寄存改目标–》

  3. 否,进行一次年青代GC,youngGC;是,寄存到Young区,分配目标内存–》

  4. YoungGC之后看看Eden Survivor是否寄存得下,寄存得下就进入年青代Young区,寄存目标内存。—》

  5. 放不下则晋升为老时代,Old区放得下则分配目标内存;放不下则FullGC(对老时代的区域目标进行废物收回,也便是区域存满了,则进行整理,废物目标整理掉,获取内存) —》

  6. FullGC之后查看Old区是否放得下,Old区放得下则分配目标内存;不然OOM—》

让人一看就懂的JVM之年轻代(Young)、老年代(Old)

年青代中为什么会有两个Survivor区域

当Eden区满了之后,会进行一次废物收回Minor GC,将存活下来的目标复制到Survivor0区,当Survivor0区满了,再次进行废物收回,存活下来的复制进入Survivor1区。Survivor1区满了,又复制进Survivor0区,循环往复。

  1. 由于大部分新目标很快就会被开释,所以将它们分配到一个时刻短的区域(Eden)中能够有效地削减废物收回的频率。
  2. 将Survivor区划分为两个部分能够交替使用,然后削减了废物收回时需要扫描的目标数量,然后削减了废物收回的时刻。

文章全为个人理解,如果发现部分跟你所知道的有出入,欢迎在评论区指出,欢迎探讨。