用 Java 创建 100 万个对象,都会存储在堆中吗?

1、想一想

在小编刚开始学习Java语言的时候,然后知道了JVM,之前老师一直说Java中的实例对象就存储在JVM中的堆区。

先给大家上一张JVM的内存模型图,这图应该很熟悉吧,应该对每一块干什么用的多多少少也有了解个大概。

过了几年,Java中的实例对象全部都是存储在堆区的概念,已经被小编我深深的烙印在心中。

还记得小编在面试的时候,遇到过一个类似的问题:

面试官:你知道Java的实例对象是存储在JVM中哪个区域么?

小编:堆区。

面试官:那假设在方法中new了一个百万个对象,也还是全部存储在堆区吗?

那么关键的地方来了,当初对于年少无知的小编来说,哪会想那么多,就死脑筋认为只要是实例对象就只会存储在堆区中。

如果小伙伴你们也不知道答案,那么带着这个问题,来看实际操作一波吧。

typescript 复制代码
public class Test_1 {

    public static void main(String[] args) {
       for (int i=0;i < 10000;i++){
           create();
       }
        while (true);

    }

    public static void create(){
        Test_1 test = new Test_1();
    }
}

在代码中,循环了1w次,通过HSDB工具(HSDB可以查看JVM在运行时数据区的内容),很明显能看出,在堆区中,确实存在1w个Test_1对象,那么现在改成把循环改成100w,再看看。

这下好了,count并没有达到100w个,最初小编想的是是不是被GC回收了,然后打印GC日志也没有发现。

那么问题来了,剩下的对象跑哪儿去了???

2、看一看

其实这里就涉及到一个知识点,叫做:逃逸分析,默认逃逸分析是开启的,我们先把逃逸分析关闭掉,再试试。

把逃逸分析关闭之后,通过查看对象,这下总算有100w个了。

3、什么是逃逸分析?

用官方的话来说,逃逸分析是一种确定指针动态范围的方法,可以分析在程序的哪些地方可以访问到指针。这里的指针可以理解成java的实例对象的引用地址,而指针动态范围可以理解为对象的访问修饰符(public、private等)。

上面那样的解释估计很多小伙伴都不懂,用代码来举个例子。

在start方法中,new了一个Test_1对象,很明显test_1这个对象是不是只能在start()方法中使用,其他地方都不能够使用。

这种对象就可以理解为不逃逸对象,因为它不能被其他地方访问到。

typescript 复制代码
public class Test_1 {

	public static void main(String[] args) {
		start();
	}

	public static void start() {
	   Test_1 test_1 = new Test_1();
	}
}

那现在将start方法改一下,把test_1这个对象返回出去,那么这个对象就是可以理解为一个逃逸对象,因为它被返回出去了,只要是调用了start这个方法,就可以拿到这个对象,被其他地方访问到。

或者说当一个实例对象的引用指针被多个方法或线程引用时,我们称这个指针发生了逃逸。

csharp 复制代码
	public static Test_1 start() {
		Test_1 test_1 = new Test_1();
		return test_1;
	}

最后通过这种逃逸和不逃逸的现象,来进行分析,就称之为:逃逸分析。

4、栈上分配

栈上分配就是基于逃逸分析这个分析,最后分析出来的一种优化方式,最大的好处应该是减少gc的压力,把那些不逃逸的对象分配在栈上。这样逃逸分析完后可以确定哪些变量可以分配在栈上,栈的分配比堆快,性能好。

这样就像本文一开始演示的一样,100w对象并没有全部在堆中,而把逃逸分析关闭了,就都放在堆中了。

ruby 复制代码
 逃逸分析可以通过这个参数控制,-XX:+/-DoEscapeAnalysis,+就是表示开启,-就是表示关闭。

下次如果再遇到问对象是不是全部放在堆上堆这种问题,可不要直接说都放在堆上。

当然栈上分配只是其中一种优化,还有包括标量替换 、锁消除等等,在逃逸分析的时候,如果你定义的对象的方法上有同步锁,但在运行时,却只有一个线程在访问,此时逃逸分析后的机器码,会去掉同步锁运行。

相关推荐
笃行3501 天前
集中式与分布式,KingbaseES 的四种形态共用一套内核
前端
陈随易1 天前
Vue 编译器换掉 source map,快了三四成
前端·后端·程序员
ZhengEnCi1 天前
12 种高级 UI 交互效果及对应 AI 提示词:从按压回弹到底部抽屉的物理感教学
前端·css·交互设计
IT_陈寒1 天前
Redis大key删除为什么会导致服务卡顿?我的线上事故复盘
前端·人工智能·后端
用户2705077725241 天前
MCP 最小 Server 实测:3 个 JSON-RPC 报错与修法
前端
用户499335025071 天前
一人VIP账号多人共用:Web 代理里的会话共享怎么实现
前端
用户老李1 天前
无线电自学教程 05:第一台收音机——从矿石机到 SDR
前端
IPIPD1 天前
Node.js请求遇到503怎么重试?先解析Retry-After,再做有上限退避
前端
葡萄城技术团队1 天前
dsh-spreadjs-editor 的集成链路:把 SpreadJS Designer 嵌进 Agent 工作台
前端
FlyWIHTSKY1 天前
vue2和vue3有什么区别,用法上有哪些区别
前端·javascript·vue.js