写点什么

JVM 的内存分代,这篇文章帮你理一理

用户头像
Java鱼仔
关注
发布于: 2021 年 01 月 20 日

听说微信搜索《Java 鱼仔》会变更强哦!

本文收录于JavaStarter ,里面有我完整的 Java 系列文章,学习或面试都可以看看哦


(一)JVM 分代


堆内存是 JAVA 虚拟机所管理的内存最大的一块,Java 堆被所有线程共享,几乎所有的对象实例都是在堆中分配内存,因此 Java 的堆是垃圾回收的主要区域。


JVM 的内存分代讲的就是堆内存的分代,为了更加高效的回收垃圾,将内存划分为了多个 generation(代)。


JVM 堆可以划分为新生代、老年代、永久代(JDK1.7),在 JDK1.8 中,永久代被元空间(Metaspace)所代替,并且元空间已经不在堆中了。下面我们会讲两者的区别


(二)永久代和元数据的区别


永久代是 HotSpot 虚拟机特有的概念,并且在 JDK1.8 之后,永久代就彻底消失了。


永久代存储类信息、常量、静态变量、即时编译器编译后的代码等数据,并且永久代必须指定大小限制,因此就会导致性能问题和内存溢出的问题。永久代会给 GC 带来不必要的复杂性。


元空间的本质和永久代类似,但是元空间并不在堆中,而是直接使用了本地内存,元数据可以设置限制,也可以不设置,它的大小仅受本地内存限制。


(三)什么是新生代和老年代


新生代和老年代是垃圾回收最主要的区域,我们也主要来讲解这两个区域,看下图



新生代和老年代都在堆内存中,新生代和老年代所占的默认比例为 1:2,其中一个新生代又由一个 Eden 区+两个 survivor 区组成,默认比例为 8:1:1。至于为什么这么设置,就和所采用的垃圾回收算法有关。


首先讲一下新生代,YoungGC 对应于新生代,第一次 YGC 只回收 eden 区域,回收后大多数(百分之九十八左右)的对象会被回收,活着的对象通过复制算法进入 Survivor0(后续用 S0 和 S1 代替)。再次 YGC 后,eden+S0 中活着的对象进入 S1。再次 YGC,eden+S1 中活着的对象进入到 S0。依次循环。看到这里我相信你已经明白了为什么要设置两个 survivor 区域了。


当一个对象的年龄(经历的 YGC 次数)足够时(传统的垃圾回收器一般是 15,CMS 垃圾回收器是 6),进入老年代


如果遇到一个对象 S 区装不下,则直接进入老年代。


老年代的垃圾回收或称叫做 FullGC,当老年代空间不足时,就会触发 FullGC;另外,如果元空间区域的内存达到了所设定的阈值-XX:MetaspaceSize=,也会触发 FullGC。


FullGC 采用的是标记整理算法,这个算法的效率是比较低的,因为它要标记出或者的对象,然后移到内存的一侧,最后再清空区域外的内存。这个过程会十分消耗时间。


因此优化 JVM 最重要的一点就是优化 FGC,尽可能的不要执行 FGC。


发布于: 2021 年 01 月 20 日阅读数: 22
用户头像

Java鱼仔

关注

你会累是因为你在走上坡路 2020.12.26 加入

微信搜索《Java鱼仔》

评论

发布
暂无评论
JVM的内存分代,这篇文章帮你理一理