内存分配与回收技术

简言

Java技术体系提倡的自动内存管理最终可以归结为自动化的解决了两个问题:给对象分配内存以及回收分配给对象的内存。对象内存的分配,往大方向讲,就是在堆上分配,对象主要分配在新生代的Eden区上,如果启动本地线程分配缓冲,将按线程优先在TLAB上分配。少数情况下也可能直接进入老年代中。

  1. 对象优先分配在Eden区
    大多数情况下,对象在新生代Eden区中分配。当Eden区内存空间不够分配时,虚拟机将发起一次MinorGC.
    新生代内存区域被划分为Eden、Survivor(form\to)三大区域,可通过参数对设定Eden与Survivor区域大小的比值
    新手代大多数情况下朝生夕死,因此MinorGC非常频繁,一般回收速度也较快。
    MajorGC\FullGC经常会至少伴随一次的MinorGC(但并非绝对,取决于具体的实现),FullGC较MinorGC要慢上10以上
  2. 大对象直接进入老年代
    所谓大对象是指需要大量连续内存空间的Java对象,最典型的就是很长的字符串以及数组。大对象的出现,经常会导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间来安置它们。
    虚拟机提供参数,令大于这个参数的对象直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制(新生代采用内存复制算法)
  3. 长期存活的对象将进入老年代
    虚拟机为每个对象设置一个年龄计数器。在Eden出生时,遇到第一次GC时年龄设定为1,此后在Survivor区每遭遇一次GC年龄+1,当达到年龄阈值时自动进入老年区(阈值默认15,可自主设定)
  4. 动态对象年龄判断
    为更好地适应不同程序的内存情况,虚拟机并不是永远地要求对象的年龄必须达到MaxTenuringThreshold才能晋升老年代,如果Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需达到设定年龄。
  5. 空间分配担保
    在发生MinorGC之前,虚拟机会检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果这个条件成立,那么MinorGC可以确保是安全的。
    如果不成立,则查看虚拟机HandlePromotionFailure设置值是否允许担保失败
    如果允许,那么会继续检查老年代最大连续可用空间是否大于历次晋升到老年代对象的平均大小,如果大于则尝试一次MinorGC,尽管这次GC有风险(该次晋升平均值比历次大,MinorGC失败,进入FullGC);
    如果小于或者HandlePromotionFailure不允许担保失败,这是要改为进行一次FullGC
发布了28 篇原创文章 · 获赞 3 · 访问量 1597

猜你喜欢

转载自blog.csdn.net/qq_43044875/article/details/104243717