用 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,+就是表示开启,-就是表示关闭。

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

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

相关推荐
Csvn32 分钟前
框架性能优化
前端
回眸&啤酒鸭2 小时前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户69371750013842 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员2 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
小兔子2 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端
IT_陈寒3 小时前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
guslegend4 小时前
脚手架原理与本地调试:从 bin 软链接到 npm link
前端·npm·node.js·脚手架·前端工程化
海码事务所4 小时前
Google Play 新个人开发者账号上架指南:12 人连续 14 天封闭测试怎么做?
前端
田威AI4 小时前
图片内文字翻译的规格:输入输出、保真、自动化、时间与费用
前端·计算机视觉
不可能片场4 小时前
命令行中文变问号 我用环境变量救了场
前端·electron