|
1. 简介
为了以最佳方式运行应用程序,JVM 将内存划分为栈内存和堆内存。每当我们声明新变量和对象、调用新方法、声明字符串或执行类似操作时,JVM 都会从栈内存或堆空间为这些操作指定内存。
在本文中,我们将检查这些内存模型。首先,我们将探索它们的主要功能。然后我们将了解它们是如何存储在 RAM 中的,以及在哪里使用它们。最后,我们将讨论它们之间的主要区别。
2.Java中的堆栈内存
Java中的栈内存用于静态内存分配和线程的执行。它包含方法中的原始值以及方法中的对象引用。
对该内存的访问是按后进先出 (LIFO) 顺序进行的。每当我们调用新方法时,都会在堆栈顶部创建一个新块,其中包含特定于该方法的值,例如原始变量和对对象的引用。
当方法完成执行时,其相应的栈帧被刷新,流程返回到调用方法,并且空间可用于下一个方法。
2.1 栈内存的主要特性
栈内存的一些特性包括:
- 它分别随着新方法的调用和返回而增长和缩小。
- 栈中的变量仅在创建它们的方法正在运行时才存在。
- 当方法完成执行时,它会自动分配和释放。
- 如果此内存已满,Java 将抛出 java.lang.StackOverFlowError。
- 与堆内存相比,访问此内存的速度更快。
- 该内存是线程安全的,因为每个线程都在自己的栈中运行。
3. Java 中的堆空间
堆空间用于在运行时对 Java 对象和 JRE 类进行动态内存分配。新对象总是在堆空间中创建,对这些对象的引用存储在栈内存中。
这些对象具有全局访问权限,我们可以从应用程序中的任何位置访问它们。
我们可以将这个内存模型分解成更小的部分,称为世代,它们是:
- 年轻代 - 这是所有新对象被分配和老化的地方。填满时会发生次要垃圾收集。
- 老年代 - 这是存储长期存活对象的地方。当对象存储在年轻代时,会设置对象年龄的阈值,当达到该阈值时,对象会被移动到老年代。
- 永生代 - 这包括运行时类和应用程序方法的 JVM 元数据。
3.1 Java 堆内存的主要特性
堆空间的一些特性包括:
- 它是通过复杂的内存管理技术访问的,包括年轻代、老代和永生代。
- 如果堆空间已满,Java 将抛出 java.lang.OutOfMemoryError。
- 访问此内存比栈内存慢
- 与栈相比,此内存不会自动释放。它需要垃圾收集器来释放未使用的对象,以保持内存使用的效率。
- 与栈不同,堆不是线程安全的,需要通过正确同步代码来保护。
4. 例子
基于我们目前所学的,让我们分析一个简单的 Java 代码来评估这里如何管理内存:
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);
}
}让我们逐步分析一下:
- 当我们进入 main() 方法时,会在栈内存中创建一个空间来存储该方法的原语和引用。
- 栈内存直接存储整数 id 的原始值。
- Person 类型的引用变量 person 也将在栈内存中创建,它将指向堆中的实际对象。
2. 从 main() 调用参数化构造函数 Person(int, String) 将进一步在栈顶分配内存。里面将存储:
- 栈内存中调用对象的 this 对象引用
- 栈内存中的原始值 id
- String 参数名称的引用变量,它将指向堆内存中字符串池中的实际字符串
3. main() 方法是进一步调用 buildPerson() 静态方法,其进一步在栈内存中分配。这将再次以上述方式存储变量。
4. 堆内存将存储所有实例变量新创建的 Person 类型的对象 person。
让我们看一下下图中的这种分配:

5. 总结
在结束本文之前,让我们总结一下 Stack Memory 和 Heap Space 的区别:
参数 | 栈内存 | 堆空间 | 应用程序 | 栈是部分使用的,在线程执行期间一次一个 | 整个应用程序在运行时使用堆空间 | 大小 | 栈有大小限制,取决于操作系统,通常小于 Heap | Heap 没有大小限制 | 存储 | 只存储原始变量和对堆空间中创建的对象的引用 | 所有新创建的对象都存储在这里 | 顺序 | 使用后进先出 (LIFO) 内存分配系统 | 访问该内存通过复杂的内存管理技术访问,包括年轻代、老年代和永久代。 | 生命周期 | 栈内存只在当前方法运行时存在 | 堆空间在应用程序运行时存在 | 效率 | 与堆相比分配速度快得多 | 与栈相比分配速度慢 | 分配和释放 | 当一个方法被调用和返回时,这个内存会自动分配和释放 | 堆空间是在垃圾收集器创建。当它们不再被引用时释放 | 栈和堆是 Java 分配内存的两种方式。在本文中,我们了解了它们的工作原理,以及何时使用它们来开发更好的 Java 程序。 |
|