JVM堆内存管理小总结

6 篇文章 0 订阅

JVM堆内存管理小总结

1. JVM堆内存分代区域与大小比例

注:Java8常用比例

    区域    eden    survivor1    survivor2    tenured
    比例    8       1            1                               #  默认
           ---------young-----------------   ---old---
    比例            1                            2                #  默认
    比例            1                            3
    比例            3                            8

2. 垃圾收集算法、垃圾收集器

  • 如何判断一个对象是否可回收
    • 引用计数(无法解决A与B对象相互引用的问题)
    • 根可达分析(正向可达)(根:虚拟机栈中的对象、本地方法栈中的对象、运行时常量池中的对象、静态引用对象、Clazz对象等)
  • 垃圾回收算法
    • Mark-Sweep 标记清除(简单,但易产生碎片空间。没有足够的连续空间时,大对象不容易分配)
    • Copying 复制(复制效率高,但会浪费一半空间)
    • Mark-Compact 标记整理(有效解决空间碎片问题,但是整理需要耗时,效率比Copy略低)
  • 垃圾收集器
    • Young:
      • Serial(串行垃圾回收)
      • ParNew(多线程版的Serial)
      • ParallelScavenge(带自适应的ParNew)
    • Old:
      • CMS(并发垃圾收集)
      • SerialOld(老年代版的Serial)
      • ParallelOld(老年代版的ParallelScavenge)
    • Young-Old:
      • G1 (堆内存分为N个块,和其他算法不同)
    • 示意图(来自互联网)
      在这里插入图片描述
  • 垃圾收集器的特性表(来自互联网)
    垃圾收集器
  • 垃圾回收时的串行、并行、并发
    • 串行:GC以单线程的方式回收对象,用户线程停止运行(STW)
    • 并行:GC以多线程的方式回收对象,用户线程停止运行(STW)
    • 并发:GC以多线程的方式回收对象,用户线程与GC线程交替执行
    • 举例:CMS中 (初始标记STW + 并发标记 + 重新标记STW + 并发清理)

3. 一个对象在堆内存中的生命周期

  • 判断-XX:PretenureSizeThreshold,决定是大对象还是小对象(默认为0,直接在eden区分配)

  • 小的对象 —> Eden区

    • —> Eden区内存足够 —> 正常运行,等待发生GC
    • —> Eden区内存不够 —> Minor GC
      1. —> 一次Minor GC后, 如果没被回收 —> survivor1区
      2. —> 一次Minor GC后, 如果没被回收 —> survivor2区
      3. —> 一次Minor GC后, 如果没被回收 —> survivor1区
      4. —> 一直这样交替循环, 达到某个条件 —> old区
    • 进入Old区的条件: 1.长期存活的对象晋升到老年代(MaxTenuringThreshold) 2.动态对象年龄判定
  • 大的对象 —> Old区

    1. —> Old区满了—> Major GC
    2. —> GC后,空间仍然不足 —> java.lang.OutOfMemoryError: Java heap space
  • 【注意的点】

    • 当一个对象需要进入Old区时,先判断“老年代最大可用的连续空间>新生代所有对象总空间”
      • 是,那么安全,直接进入(在此前面会执行Minor GC)
      • 否,看对象进入Old区是否需要做“空间分配担保”(-XX:+HandlePromotionFailure,JDK 6 Update 24后无效)
        • 如果需要做担保,判断“老年代最大可用的连续空间>历次晋升到老年代对象的平均大小”
          • 是,尝试进行Minor GC (如果失败,再进行Major GC)
          • 否,进行Major GC
        • 如果不需要担保,直接Major GC
    • 相关源码(Java1.6后,满足其中一个条件即可)
      // max_promotion_in_bytes 是新生代所有晋升对象总空间
      bool TenuredGeneration::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
        // 老年代最大可用的连续空间
        size_t available = max_contiguous_available();  
        // 历次晋升到老年代对象的平均大小
        size_t av_promo  = (size_t)gc_stats()->avg_promoted()->padded_average();
        // 满足其中一个条件即可
        bool res = (available >= av_promo) || (available >= max_promotion_in_bytes);
        return res;
      }
      

4. 补充:内存中实际建立一个对象的过程

注:默认开启栈优化、线程本地优化

  • 创建新对象
    • —> 如果栈空间够,那就分配到【栈】
    • —> 如果不够,判断对象是否比PretenureSizeThreshold大
    • —>—> 如果比PretenureSizeThreshold大,放【old区】
    • —>—> 如果小,看TLAB是否有空间
    • —>—>—> 如果TLAB够,那就分配到【TLAB】
    • —>—>—> 如果不够,放【eden区】
    • 备注:TLAB(Thread Local Allocation Buffer,它在eden区有自己的独立空间1%)
  • 几个JVM参数(默认)
    • 逃逸分析 -XX:+DoEscapeAnalysis
    • 标量替换 -XX:+EliminateAllocations
    • 线程专有对象分配 -XX:+UseTLAB
    • -XX:PretenureSizeThreshold=0,表示直接分配到Eden

5. 自制:对象在内存中分配的流程图

  • 自制流程图 ^_^

对象在内存中分配的流程图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值