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

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

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

相关推荐
生椰拿铁You1 小时前
10 —— Webpack打包模式
前端·webpack·node.js
liangshanbo12151 小时前
创建可重用React组件的实用指南
前端·javascript·react.js
gma9991 小时前
JSONCPP 数据解析与序列化
开发语言·前端·javascript·c++
sky_feiyu1 小时前
前端HTML
前端·html
随·枫1 小时前
html渲染优先级
前端·html
小扳2 小时前
Web 毕设篇-适合小白、初级入门练手的 Spring Boot Web 毕业设计项目:电影院后台管理系统(前后端源码 + 数据库 sql 脚本)
java·前端·数据库·spring boot·mysql·spring·课程设计
田本初2 小时前
从0-1逐步搭建一个前端脚手架工具并发布到npm
前端·npm·node.js
Marshall35722 小时前
Canvas 和 SVG 的高级使用与性能优化
前端·svg·canvas
Java学长-kirito3 小时前
springboot/ssm网购平台管理系统Java在线购物商城管理平台web电商源码
java·前端·spring boot
夫琅禾费米线3 小时前
JavaScript 中的 Generator 函数及其方法
开发语言·前端·javascript