java类和对象都在堆中吗_【Java面试题】Java类对象都是在堆上分配的内存吗?

0. 背景

JVM经典的内存模型想必大家都很熟悉了,我们都非常熟悉的 栈内存 + 堆内存 的结构中,引用变量和基础数据类型都是直接在栈内存上分配的,而类对象是在堆内存中分配的。

那么,面试题:

Java类对象都是在堆上分配的内存吗?

这个问题的答案是什么呢?

1. JVM虚拟机的内存结构

在回答这个问题之前,我们先回顾下JVM的虚拟机内存模型。根据JVM虚拟机的规范的定义,标准的JVM的内存分为以下几个部分:Java栈内存(一般简称为“栈内存”)

堆内存

PC程序计数器(里面永远存储下一条要被执行的虚拟机指令)

方法区

Native栈内存

其中,每一个Java线程,都会有一个调用栈,Java 的方法调用是在栈内存上通过栈帧的创建和销毁完成的,其中变量的引用和基础类型的内存分配,都是在栈内存的 栈帧 内部完成的,而对象的内存分配,则是在堆内存上面完成的。

这是一个很典型的常识,但是确不一定是绝对的(对于技术来说,哪有什么是绝对的,只要能提升性能、方便开发、方便使用,什么都能做,哈哈哈)

2. 来做一个假想

接下来,我们看一个典型的场景:

// 一个方法public void methodA() {

// 一个对象,它的引用仅限于在改方法内部 Object objectA = new Object();

String str = objectA.toString();

System.out.println("objectA: " + str);

}

在以上的示例代码中,JVM的方法 methodA 调用的过程中,假如有一个 objectA,它的创建是在 methodA 的内部,并且也在它的内部使用,objectA 的引用也没有 流出 方法 methodA 之外的其他地方。那么根据上一章的分析,我们知道, objectA 的生命周期其实和这个方法的调用是一致的了,在 medthodA 调用完成后,objectA 的生命周期也会结束,将会被随后的GC回收调内存。

在上面的这样的场景中,objectA 对象仍然是在堆内存中进行内存的分配,然后在栈内存上通过它的引用来使用它。不过,我们可以做一个假想:

假如对象objectA直接在栈内存上分配内存,那么不就可以避免在堆内存上分配内存了吗?这样做就省去了在堆内存上寻址的过程。同时也不需要依赖堆内存上面的GC来释放不再被使用的objectA的内存了。因为objectA对象的释放完全可以随着栈帧的销毁而销毁。

这个假想看起来是对虚拟机的性能有提升的,那么这个假想是成立的吗?

它是成立的,而且是有应用的。

3. JVM性能增强之 逃逸分析

在上一章节中,一个很关键的过程是,通过一种方法,来确定 objectA 的生命周期没有超过它所在的方法,也即是它没有逃逸 出它的方法。

那么,针对对象没有逃逸出它的方法范围 的使用场景,就可以进行性能优化,可以直接在栈内存上分配内存了。

这样技术在Java 8以后,已经在HotSpot 里面有实现了,详情请参考OpenJDK 的wiki页面(逃逸分析),这里就不再展开了。

除了以上提到的场景之外,关于对象的逃逸,还有以下几种范围,针对每一个逃逸范围都有不同的优化策略:对象没有逃逸出它的方法的范围;对象的栈上分配:直接在栈上分配对象,对象仍然是完整的对象,只是避免了在堆内存的GC过程。

标量替换:把一个对象打散,拆分成许多个不能再分的原始类型(比如int、float等)。

对象没有逃逸出它的线程的范围;可以优化synchronized 锁,如果没有逃逸出线程,那么可以在编译后把锁去掉;

对象会逃逸到全局的作用范围;

4. 总结

通过以上的分析,我们知道目前有些虚拟机(HotSpot)上是实现了栈上分配 的,那么对于最开始的面试题Java类对象都是在堆上分配的内存吗?

答案就是否定的了,因为对象是否在堆上分配,其实是取决于虚拟机的实现的。

所以,如果面试中遇到了这样的问题,请先三思哦~

参考资料:Java ™ HotSpot Virtual Machine Performance Enhancements​docs.oracle.comOpenJDK wiki​wiki.openjdk.java.netEscape analysis for Java​citeseerx.ist.psu.edu82c35809cf89eadc2eb53b8257a3918c.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值