JVM-(四)运行时数据区-堆内存分配
本文最后更新于:May 13, 2023 pm
积土成山,风雨兴焉;积水成渊,蛟龙生焉;积善成德,而神明自得,圣心备焉。故不积跬步,无以至千里,不积小流无以成江海。齐骥一跃,不能十步,驽马十驾,功不在舍。面对悬崖峭壁,一百年也看不出一条裂缝来,但用斧凿,能进一寸进一寸,能进一尺进一尺,不断积累,飞跃必来,突破随之。
目录
对象分配的一般过程
堆内存分布:
首先对象放在伊甸区(小对象),当伊甸区放满了之后,将会进行MinorGC。
GC仍然存活的对象,将会转移到幸存区(S0区)中,并且对象的年龄计数器将会增加1。
在GC后,伊甸区将继续存放对象。当再一次满了的时候会再次GC。这一次的GC会将伊甸区和已经存放对象部分的幸存区进行GC。然后放入另外一块未被占用的幸存区。同样对象的年龄计数器会加1。
伊甸区再次满时,再进行GC,在幸存区中的对象,如果年龄计数器达到了15(15是默认值。可以通过参数
-XX:MaxTenuringThreshold=15
进行修改设置),则将会进入老年代中。
大对象(如:数组)直接进入老年代中(对象要占的内存比伊甸区总大小还大)。当老年代内存不足以存放对象时,会触发Major GC。如果在Major GC后仍然无法进行对象的保存,则会产生OOM异常。
注意点
- 幸存区满时,不会触发Minor GC(但不代表不进行GC)。Minor GC只会在伊甸区满时才会触发,只是进行Minor GC时,会将伊甸区和幸存区中的对象都进行GC。
- 幸存区中的对象的年龄未达到阈值时也有可能提前进行老年代。
- 关于幸存区的s0、s1区:谁空谁是to区。from区才存放对象。
- 对于垃圾回收:频繁在新生代收集,很少在老年代收集,几乎不在元空间(方法区)收集。
分配特殊情况
具体也可见《JAVA知识点-Java对象的分配详解 》 。
初谈GC区别
分为Minor GC、Major GC、Full GC。
针对HotSpot VM的实现,GC按照回收区域又分为两中类型:一种是部分收集(Partial GC)、一种是整堆收集(Full GC)。
部分收集(Partial GC)
不是完整收集整个Java堆的垃圾收集。其中又分为:
- 新生代收集(MinorGC、YoungGC):只是新生代(Eden、S0、S1)的垃圾收集。
- 老年代(MajorGC、OldGC):只是老年代的垃圾收集。目前只有CMS GC会有单独收集老年代的行为。
- 混合收集(MixedGC):收集整个新生代以及部分老年代的垃圾收集。目前只有G1 GC会有这种行为。
整堆收集(Full GC)
收集整个Java堆和方法区的垃圾收集。
📢注意:很多时候Major GC会和Full GC混淆使用,需要具体分辨是老年代回收还是整堆回收。
年轻代GC(Minor GC)的触发机制
- 当年轻代空间不足时,会触发Minor GC。这里的满指的是Eden区满,而幸存区(Survivor)满不会引发GC。但每次Minor GC都会清理年轻代的内存(包括Eden区和幸存区)。
- 因为Java对象大多都是使用完就会死亡,所以Minor GC非常频繁,一般回收速度也比较快。
- Minor GC会引发STW(Stop the World),暂停其他用户线程,等垃圾回收结束后用户线程才恢复运行。
老年代GC(Major GC、Full GC)触发机制
- 指发生在老年代的GC,对象从老年代消失时,Major GC或者Full GC发生。
- 出现了Major GC,经常会伴随至少一次的Minor GC(但并非绝对的,在Parallel Scavenge收集器的收集策略中就有直接进行Major GC的策略选择过程)。也就是在老年代空间不足时,会先尝试触发Minor GC。如果之后空间还不足,则触发Major GC。
- Major GC的速度一般比Minor GC慢10倍以上,STW的时间更长。
- 如果Major GC后,内存还不足,就报OOM。
Full GC触发机制
触发Full GC有五种情况:
- 调用System.gc()时,系统建议执行Full GC,但是不必然执行。
- 老年代空间不足。
- 方法区空间不足。
- 通过Minor GC后进入老年代的平均大小大于老年代的可用内存。
- 由Eden区、S0(from)区向S1(to)区复制时,对象大小大于to区的可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。
Full GC是开发或调优中尽量要避免的。这样暂停时间会短一些。
本文作者: 墨水记忆
本文链接: https://tothefor.com/DragonOne/3933e14d.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!