Java 堆内存与逃逸分析

1. JVM 运行时数据分区

首先看一下 JVM 规范中对于 Run-Time Data Areas 的定义。

一般被称为 Java 内存模型,但是在Java 语言规范中对于 Memory Model是另外的定义。

  1. 程序计数器
  2. JVM栈
  3. 方法区
  4. 运行时常量池
  5. 本地方法栈

其中,在 Java 代码中,创建对象一般是在堆中完成,堆内存的回收由垃圾回收器(GC)完成。

2. Java 内存分配

Java 堆内存根据对象的存活周期,分为新生代、老年代、元数据区。
新生代分为 Eden 区 和 Survivor 区(又分为 from 和 to 区)。
在新建对象进行内存分配时,会优先在 Eden 区分配,程序中多线程运行时内存分配会出现竞争(CAS更新失败),于是出现了 Thread Local Allocation Buffer(TLAB),此 Buffer 大小会根据程序运行情况进行调整。每个线程在申请内存分配时,先向 Eden 区申请 TLAB 大小的空间,之后根据对象和TLAB剩余大小,选择在 TLAB 中分配、新申请TLAB分配、Eden 分配、老年代分配(-XX:PretenureSizeThreshold大于此大小的内存分配发生在 老年代)。

2.1 GC触发条件

当新生代GC(Minor GC)发生时,采用的复制算法。
新生代中只有 Eden 和 Survivor from 区存在数据,Eden 区数据拷贝到 to 去,from 区数据根据对象存活情况,拷贝到 to 区或移动到 老年代(-XX:MaxTenuringThreshold),Eden 和 from 被清空。之后交换 From 和 to 区,保证 to 区为空。
由于 Minor GC 可能会将 Eden 和 from 区中的对象移动到老年代,最极端的情况就是会出现老年代剩余空间不足以存放新生代数据(空间担保),就会出发 Major GC。

老年代GC(Major GC/Full GC)发生时,采用标记整理算法。

当 年龄1+年龄2+…+年龄n 的对象大于 Survivor 区空间的 50%(-XX:TargetSurvivorRatio),年龄大于等于n 的对象会直接进入老年区。

3. 逃逸分析与栈上分配

Java 7 之后默认开启
堆内存分配之后需要解决回收的问题,那栈呢?由于栈的结构原因,当栈进行出栈操作的时候,就会将这一部分内存回收。如果在方法调用中,频繁出现内存分配,在方法结束时候对象即可以销毁,这时候考虑可以在栈上分配内存,减少堆内存的回收压力。
在栈上进行内存分配,需要知道这部分内存不会在外部进行访问(-XX:+DoEscapeAnalysis)同时对于其中的对象进行分解,使用标量进行替换(-XX:+EliminateAllocations)。

使用以下代码进行尝试即可看到修改 -XX:+DoEscapeAnalysis-XX:+EliminateAllocations 对 GC 造成的影响。

-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-XX:+PrintGC
-Xmx10m
-Xms10m
-XX:+DoEscapeAnalysis
-XX:+EliminateAllocations
public class Test extends Base {
    public static void main(String[] args) {
        for (int i = 0; i < 1000000000; i++) {
            t.test();
        }
    }
    public void test() {
        byte[] bytes = new byte[64];
    }
}

尝试将数组大小的 64 改为 65,会有不一样的结果。

4. Android

在 Android 10 上执行以上代码,出现了频繁的 GC,并没有以上优化。

参考链接:

Run-Time Data Areas
Memory Model
Major GC和Full GC的区别是什么?触发条件呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值