为了更高效的运行应用程序,JVM 选择将内存划分为栈空间和堆空间。 每当我们声明新变量和对象、调用新方法、声明 String 或执行类似操作时,JVM 都会在栈或堆空间里面操作指定内存。
在这篇文章里面,我们将简要介绍 JVM 的内存模型以及它们的主要功能,然后我们将介绍它们是如何存储在内存里面,以及会在哪里使用到它们。最后,我们将分几个维度总结它们之间的主要区别。
JVM 中的栈空间用于静态内存分配和线程的执行。 它包含方法的原始值以及对象的引用。
对该内存的访问是按后进先出 (LIFO) 顺序进行的。每当我们调用新方法时,都会在堆栈顶部创建一个新块,其中包含特定于该方法的值,例如原始变量和对对象的引用。
当方法完成执行时,其相应的堆栈帧将被刷新,流程返回到调用方法,这样空间就又可用于下一个方法运行。
栈空间的其他一些特性包括:
堆空间用于 Java 对象在运行时的动态内存分配。新对象总是在堆空间中创建,而这些对象的引用则存储在栈空间中。
这些对象具有全局访问权限,我们可以从应用程序中的任何位置访问它们。
我们可以将这个内存模型分解成更小的部分,称为世代,它们是:
堆空间的其他一些特性包括:
基于我们目前所学的,让我们通过分析一个简单的 Java 代码来展示 JVM 如何管理内存:
class Person { int id; String name; public Person(int id, String name) { this.id = id; this.name = name; } } public class PersonBuilder { private static Person buildPerson(int id, String name) { return new Person(id, name); } public static void main(String[] args) { int id = 23; String name = "John"; Person person = null; person = buildPerson(id, name); } }
让我们逐步分析一下:
实际在内存中的分配如下图:
让我们快速总结一下栈空间和堆空间的主要区别:
参数 | 栈空间 | 堆空间 |
---|---|---|
使用场景 | 在线程执行期间使用 | 整个应用程序在运行时使用堆空间 |
大小限制 | 栈空间有大小限制,具体取决于操作系统,通常小于堆空间 | 通常没有大小限制 |
存储内容 | 仅存储原始变量和在堆空间中创建的对象的引用 | 所有新创建的对象都存储在这里 |
存取顺序 | 它使用后进先出 (LIFO) 内存分配系统进行访问 | 该内存是通过复杂的内存管理技术访问的,主要包括新生代和老年代。 |
生命周期 | 栈空间只在当前方法运行时才存在 | 只要应用程序运行,堆空间就存在 |
效率 | 与堆相比,分配速度要快得多 | 与堆栈相比分配更慢 |
分配和回收 | 当一个方法被调用和返回时,这个内存将被自动分配和回收 | 堆空间是在新对象创建时分配的,当它们不再被引用时将被回收 |
栈空间和堆空间是 Java 分配内存的两种基本方式,熟悉它们的工作原理,将有利于我们开发出高效运行的 Java 应用程序。