首先看看Chat GPT关对于在jvm中,堆是分配对象内存存储的唯一选择吗的回答

https://s.gravatar.com/avatar/0dce7254556a159b40d7e7429bab61eb?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fwx.png

<aside> 🗨️ 在Java虚拟机(JVM)中,堆是主要用于分配对象内存的区域,但并不是唯一的选择。除了堆,Java中还存在栈(Stack)和方法区(Method Area,或元空间Metaspace)等内存区域。

  1. 堆(Heap): 堆是主要用于存储对象实例的地方。通过 new 关键字创建的对象在堆上进行分配。堆的优势在于它提供了动态内存分配和垃圾回收机制,使得对象的生命周期可以比较灵活。
  2. 栈(Stack): 栈主要用于存储线程的局部变量和方法调用。基本数据类型和对象引用(而非对象本身)可以存储在栈上。栈上的内存分配和释放是由系统自动管理的,而且遵循后进先出(LIFO)的原则。局部变量在方法执行时被创建,方法结束时被销毁。
  3. 方法区(Method Area,Metaspace): 方法区用于存储类的元信息、静态变量、常量池等。在较早的JVM版本中,方法区被称为永久代(Permanent Generation,PermGen),但在Java 8之后,永久代被元空间(Metaspace)取代。元空间用于存储类相关的信息,但不用于存储对象实例。

所以,尽管堆是分配对象内存的主要区域,但在Java中有其他内存区域用于不同的目的。选择使用堆还是其他内存区域取决于数据的生命周期、访问模式以及性能需求。

</aside>

其中在栈存储的局部变量和方法调用。基本数据类型和对象引用标识需要jvm做一个筛选,这个筛选方法就叫逃逸分析(Escape Analysis)

逃逸分析简述

在《深入理解Java虚拟机》中关于Java堆内存有这样一段描述: 随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。


在Java虚拟机中,对象是在Java堆中分配内存的,这是一个普遍的常识。

但是,有一种特殊情况,那就是如果经过逃逸分析(Escape Analysis)后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需在堆上分配内存,随着方法执行的结束,栈空间就被移除了,也无须进行垃圾回收了。这也是最常见的堆外存储技术。



在JDK 6u23版本之后,Hotspot中默认就已经开启了逃逸分析。如果使用的是较早的版本,开发人员则可以通过:

代码分析

如何快速判读是否发生了逃逸分析,就看new的对象实体是否有可能在方法外被调用

代码1