让人一看就懂的JVM之年轻代(Young)、老年代(Old)
本文源自Recently祝祝,创自Recently祝祝。转载请标注出处。
此解决方式在企业中有所应用,适合Java初级开发学习,参考。
本文字数与行数,耐心阅读必有收获。
堆内存结构
堆的内存结构:
- 年轻代
- Eden区域:新建对象所在的区域
- Survivor0区:当Eden区域满的时候,进行一次Minor GC,存活对象进入Survivor0区,Eden区域存活对象会与Survivor区域合并
- Survivor1区:当Survivor0区满了,也会进行一次Minor GC ,存活对象复制进Survivor1区。Survivor1会根据对象年龄判断进入老年代还是继续复制到Survivor另一个区域里边。
- 老年代
- 老年代:当Eden区域创建的对象,MinorGC之后超过Survivor百分之五十内存的对象会进入老年代。经过15次Minor GC还存活的对象会进入老年代。
- 元空间:在1.8之后永久代被元空间取代。存取数据更灵活。
- 存储元数据:例如:类名、访问修饰符、方法信息、字段信息等数据信息
- 元空间存储的就是运行时常量池的数据
为什么堆内存要分年轻代和老年代?
-
主要原因--》分代收集理论:将容易回收对象放入年轻代,不容易回收对象存放进入老年代。为了提升垃圾回收的效率,减少垃圾回收的频次和时间。
-
根据分代收集理论,分为强分代假说、弱分代假说。将容易消亡的对象存放到弱分代中,存活时间长的存放到强分代中。为了效率更高的进行垃圾回收,根据生命周期的长短分为年轻代和老年代两类。
-
年轻代
- 年轻代生命周期短,更容易被进行垃圾回收,需要更多次的进行垃圾回收。
- 年轻代分为三个区Eden区、Surivivor0区、Survivor1区。新创建的对象会先进入Eden区,当Eden区满了之后,会进行一次垃圾回收Minor GC,将存活下来的对象复制到Survivor0区,当Survivor0区满了,再次进行垃圾回收,存活下来的复制进入Survivor1区。Survivor1区满了,又复制进Survivor0区,循环往复。每复制进入Survivor区中年龄+1,当年龄达到15的时候就会被存放到老年代。
-
老年代
- 生命周期长,更少的对象需要被回收,不需要频繁的进行垃圾回收。
- 对象从年轻代进入老年代,当老年代满了的时候,会进行一次Major GC ,全局垃圾回收。
-
老年代的Major GC与年轻代的MinorGC 相比不需要那么频繁而且但是耗时会更长,根据以上特点将内存区域分为老年代和年轻代。
年轻代进入老年代的整个过程
-
新对象申请--》
-
进入Eden区,判断内存大小是否可以存放改对象--》
-
否,进行一次年轻代GC,youngGC;是,存放到Young区,分配对象内存--》
-
YoungGC之后看看Eden Survivor是否存放得下,存放得下就进入年轻代Young区,存放对象内存。---》
-
放不下则晋升为老年代,Old区放得下则分配对象内存;放不下则FullGC(对老年代的区域对象进行垃圾回收,也就是区域存满了,则进行清理,垃圾对象清理掉,获取内存) ---》
-
FullGC之后查看Old区是否放得下,Old区放得下则分配对象内存;否则OOM---》
年轻代中为什么会有两个Survivor区域
当Eden区满了之后,会进行一次垃圾回收Minor GC,将存活下来的对象复制到Survivor0区,当Survivor0区满了,再次进行垃圾回收,存活下来的复制进入Survivor1区。Survivor1区满了,又复制进Survivor0区,循环往复。
- 由于大部分新对象很快就会被释放,所以将它们分配到一个短暂的区域(Eden)中可以有效地减少垃圾回收的频率。
- 将Survivor区划分为两个部分可以交替使用,从而减少了垃圾回收时需要扫描的对象数量,从而减少了垃圾回收的时间。
文章全为个人理解,如果发现部分跟你所知道的有出入,欢迎在评论区指出,欢迎探讨。
转载自:https://juejin.cn/post/7226153290051174460