JVM-堆-内存分配策略-06

JVM-堆-内存分配策略-06,第1张

JVM-堆-内存分配策略-06 内存分配策略

如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到survivor空间中,并将对象年龄设为1。对象在survivor区中每熬过一次MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁,其实每个JVM、每个GC都有所不同)时,就会被晋升到老年代

对象晋升老年代的年龄阀值,可以通过选项-xx:MaxTenuringThreshold来设置

针对不同年龄段的对象分配原则如下所示:

优先分配到Eden

开发中比较长的字符串或者数组,会直接存在老年代,但是因为新创建的对象 都是 朝生夕死的,所以这个大对象可能也很快被回收,但是因为老年代触发Major GC的次数比 Minor GC要更少,因此可能回收起来就会比较慢

大对象直接分配到老年代

尽量避免程序中出现过多的大对象,一旦出现大对象,因为需要一段很长的连续的内存空间,此时尽管剩下的地方还很多,但是如果都是分段的,没有连续的大量空间,就需要触发Minor GC 或major GC,引发STW。而且更糟糕的是,这个大对象还是朝生夕死的,很快会被回收,白GC了。

长期存活的对象分配到老年代

动态对象年龄判断

如果survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代,无须等到MaxTenuringThreshold 中要求的年龄。

空间分配担保: -Xx:HandlePromotionFailure

也就是经过Minor GC后,所有的对象都存活,因为Survivor比较小,所以就需要将Survivor无法容纳的对象,存放到老年代中。

为对象分配内存:TLAB 问题:堆空间都是共享的么?

不一定,因为还有TLAB这个概念,在堆中划分出一块区域,为每个线程所独占

为什么有TLAB?

TLAB:Thread Local Allocation Buffer,也就是为每个线程单独分配了一个缓冲区

堆区是线程共享区域,任何线程都可以访问到堆区中的共享数据

由于对象实例的创建在JVM中非常频繁,因此在并发环境下从堆区中划分内存空间是线程不安全的

为避免多个线程 *** 作同一地址,需要使用加锁等机制,进而影响分配速度。

什么是TLAB

从内存模型而不是垃圾收集的角度,对Eden区域继续进行划分,JVM为每个线程分配了一个私有缓存区域,它包含在Eden空间内。

多线程同时分配内存时,使用TLAB可以避免一系列的非线程安全问题,同时还能够提升内存分配的吞吐量,因此我们可以将这种内存分配方式称之为快速分配策略。

据我所知所有OpenJDK衍生出来的JVM都提供了TLAB的设计。

尽管不是所有的对象实例都能够在TLAB中成功分配内存,但JVM确实是将TLAB作为内存分配的首选。

在程序中,开发人员可以通过选项“-Xx:UseTLAB”设置是否开启TLAB空间。默认是开启状态

默认情况下,TLAB空间的内存非常小,仅占有整个Eden空间的1,当然我们可以通过选项“-Xx:TLABWasteTargetPercent”设置TLAB空间所占用Eden空间的百分比大小。

一旦对象在TLAB空间分配内存失败时,JVM就会尝试着通过使用加锁机制确保数据 *** 作的原子性,从而直接在Eden空间中分配内存。

TLAB分配过程

对象首先是通过TLAB开辟空间,如果不能放入,那么需要通过Eden来进行分配

 

如果对象很大,大到即使新生代发生minorGC依然无法存放,便不触发minor GC,直接放入老年代。 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5712557.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存