面试官:是不是所有的对象和数组都会在堆内存分配空间

2019-08-20 11:46:52 浏览数 (1)

熟看了java编译原理等多本大神级别书籍后,小明信心满满的去面试字节跳动了,跳动的面试官说:小伙,来给我讲一下是不是所有的对象和数组都会在堆内存分配空间?

小明不由一喜,昨天正好我看了相关jvm的书籍,堆中主要存放对象,即通过new关键字创建的对象。当场哈哈大笑:没错,面试官你太威武了,所有的对象和数组都存在堆中。当场从jvm原理:方法区、虚拟机栈、本地方法栈、堆、程序计数器讲起,说到堆内主要存放对象,栈中存放一些基本类型的变量数据(int/short/long/byte/float/double/Boolean/char)和对象引用。内心狂喜,但实际是这样吗?

正好在前几天发了两篇关于java逃逸分析的文章,但是发现大家看的不多,当大家都在最求mysql优化,mongo优化等等的时候,有没有想过jvm有一种优化技术叫做逃逸分析。

1. JVM优化之逃逸分析与分配消除

2. JVM优化之逃逸分析及锁消除

jvm在编译阶段引入了JIT(即时编译) 技术,而随着这种技术的成熟,栈上分配、标量替换优化技术也产生了一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。

为了方便大家理解逃逸分析,给大家献上两段网上找的代码

大家可以观察,在第一段代码中StringBuffer对象被该方法之外的给利用了,也就是该对象逃逸出了该方法体。相反第二段代码就将对象的值转化为常量返回给了调用方,该对象就在内部被消化了,jvm的逃逸分析也针对的就是这种情况。

代码语言:javascript复制
在Java代码运行时,通过JVM参数可指定是否开启逃逸分析,
 -XX: DoEscapeAnalysis :表示开启逃逸分析
 -XX:-DoEscapeAnalysis : 表示关闭逃逸分析

下面我们开始举个例子:

这是一段测试代码,其中User对象只被alloc调用了。我们接下来重启两次jvm,一次执行代码

-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX: PrintGCDetails -XX: HeapDumpOnOutOfMemoryError

另一次执行:

-Xmx4G -Xms4G -XX: DoEscapeAnalysis -XX: PrintGCDetails -XX: HeapDumpOnOutOfMemoryError

我们通过jmap命令来查看结果:第一次结果

第二次结果:

不难看出在开启逃逸分析的情况下 堆内存中的对象数量为8万多比没开启的情况下的100万少了非常多。

所以我们也基本上能看出,跳动的面试官想问的不是书本上的死知识。

总结一下:

在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。但是,有一种特殊情况,那就是如果经过逃逸分析后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,也无须进行垃圾回收了。

参考:Hollis公众号

0 人点赞