概述
Minor GC、Major GC、Full GC
JVM 在进行 GC 时,并非每次都对堆内存(新生代、老年代;方法区)区域一起回收的,大部分时候回收的都是指新生代。
- 部分收集:不是完整收集整个 Java 堆的垃圾收集。其中又分为:
- 新生代GC(Minor GC/Young GC):发生在新生代的垃圾回收动作。由于Java对抓了大都具有朝生夕死的特性,所以Minor GC非常频繁,回收速度也很快。
- 老年代GC(Major GC/Old GC):发生在老年代的垃圾回收,经常会伴有至少一次的Minor GC。
- 目前,只有 CMS 和 GC 会有单独收集老年代的行为
- 很多时候 Major GC 会和 Full GC 混合使用
- 混合收集(Mixed GC):收集整个新生代以及部分老年代的垃圾收集
- 目前只有 G1 GC 会有这种行为
- 整堆收集(Full GC):收集整个 Java 堆和方法区的垃圾
内存分配策略
-
对象优先在Eden分配
- 对象在新生代Eden区分配,当Eden区没有足够空间时,发起一次Minor GC
-
大对象直接进入老年代
- 大对象:需要大量连续内存的Java对象(长字符串或数组)
-XX:PretenureSizeThreshold
,大于此值的对象直接在老年代分配,避免在 Eden 区和 Survivor 区之间的大量内存复制。
-
长期存活的对象进入老年代
- 对象存在年龄计数器。对象在Eden出生并经过Minor GC依然存活,将移动到Survivor中,年龄增加一岁,增加到一定年龄则移动到老年代中。
-XX:MaxTenuringThreshold
用来定义年龄的阈值。
-
动态对象年龄控制
- 虚拟机并不是永远地要求对象的年龄必须达到 MaxTenuringThreshold 才能晋升老年代,如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代。
-
空间分配担保
-
在Minor GC之前,虚拟机会检查老年代的最大可用连续空间是否大于新生代的对象总空间。若大于,则Minor GC是安全的。
-
否则,虚拟机会查看
HandlerPromotionFailure
的值是否允许担保失败。如果允许,虚拟机检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小。若大于,则尝试进行一次Minor GC,此时的Minor GC是有风险的。 -
如果小于,或者
HandlerPromotionFailure
不允许冒险,则改为进行一次Full GC。 -
取平均值(经验值)进行比较其实是一种动态概率的手段。如果某次Minor GC后存活的对象激增,依然会导致担保失败(HandlePromotionFailure),只好在失败后重新发起一次Full GC。
-
Full GC触发条件
-
调用
System.gc()
-
老年代空间不足
-
空间分配担保失败
-
JDK 1.7及以前的永久代空间不足
在 JDK 1.7 及以前,HotSpot 虚拟机中的方法区是用永久代实现的,永久代中存放Class的信息、常量、静态变量等数据。
当系统中要加载的类、反射的类和调用的方法较多时,永久代可能会被占满,在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了,那么虚拟机会抛出 java.lang.OutOfMemoryError。
-
Concurrent Mode Failure
执行 CMS GC 的过程中同时有对象要放入老年代,而此时老年代空间不足(可能是 GC 过程中浮动垃圾过多导致暂时性的空间不足),便会报 Concurrent Mode Failure 错误,并触发 Full GC。
最后
以上就是震动高山为你收集整理的JVM 的 内存分配与回收策略的全部内容,希望文章能够帮你解决JVM 的 内存分配与回收策略所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复