1.简介
为了以最佳方式运行应用程序,JVM将内存分为堆栈和堆内存。每当我们声明新的变量和对象,调用新的方法,声明String或执行类似的操作时,JVM就会从堆栈内存或堆空间中为这些操作指定内存。
在本教程中,我们将讨论这些内存模型。我们将列举它们之间的一些关键区别,它们在RAM中的存储方式,它们提供的功能以及在何处使用它们。
2. Java中的堆栈内存
Java中的堆栈内存用于静态内存分配和线程执行。它包含特定于方法的原始值以及对从该方法引用的堆中对象的引用。
对该存储器的访问按后进先出(LIFO)顺序进行。每当调用新方法时,都会在堆栈顶部创建一个新块,其中包含特定于该方法的值,例如原始变量和对对象的引用。
当方法完成执行时,将刷新对应的堆栈帧,流程返回到调用方法,并且下一个方法可以使用空间。
2.1。堆栈存储器的主要功能
除了我们到目前为止讨论的内容以外,以下是堆栈存储器的其他一些功能:
- 随着分别调用和返回新方法,它会增长和收缩
- 堆栈中的变量仅在创建它们的方法正在运行时才存在
- 方法执行完成后会自动分配和释放
- 如果此内存已满,则Java抛出java.lang.StackOverFlowError
- 与堆内存相比,对该内存的访问速度很快
- 该内存是线程安全的,因为每个线程都在自己的堆栈中运行
3. Java中的堆空间
Java中的堆空间用于在运行时为Java对象和JRE类动态分配内存。新对象总是在堆空间中创建,并且对该对象的引用存储在堆栈内存中。
这些对象具有全局访问权限,可以从应用程序中的任何位置进行访问。
此内存模型进一步细分为称为几代的较小部分,它们是:
- 年轻一代–在这里分配和老化所有新对象。填满后会发生次要垃圾收集
- 旧的或永久的一代–这是保存长期存在的对象的位置。当对象存储在“年轻代”中时,将设置对象年龄的阈值,当达到该阈值时,该对象将移至旧代
- 永久生成–包含用于运行时类和应用程序方法的JVM元数据
本文还将讨论这些不同的部分– JVM,JRE和JDK之间的区别。
我们总是可以根据需要来操纵堆内存的大小。有关更多信息,请访问链接的Baeldung文章。
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 也将在堆栈内存中创建,该内存将指向堆中的实际对象
- 从main()对参数化构造函数Person(int,String)的调用 将在上一个堆栈的顶部分配更多内存。这将存储:
- 堆栈内存中调用对象的this对象引用
- 堆栈存储器中的原始值 id
- String参数名称的引用变量,它将指向堆内存中字符串池中的实际字符串
- 的主要方法进一步调用buildPerson()静态方法中,其进一步分配将在堆栈存储器上的前一个的顶部。这将再次以上述方式存储变量。
- 但是,对于类型为 Person的新创建的对象 person,所有实例变量都将存储在堆内存中。
下图说明了这种分配:
5.总结
在总结本文之前,让我们快速总结一下堆栈内存和堆空间之间的区别:
参数 | 堆栈记忆体 | 堆空间 |
应用 | 堆栈用于部分,在线程执行期间一次使用一个 | 整个应用程序在运行时使用堆空间 |
尺寸 | 堆栈的大小限制取决于操作系统,通常小于堆 | 堆没有大小限制 |
存储 | 仅存储原始变量和对在堆空间中创建的对象的引用 | 所有新创建的对象都存储在这里 |
订购 | 使用后进先出(LIFO)内存分配系统对其进行访问 | 可通过复杂的内存管理技术访问此内存,这些技术包括年轻一代,老一代或终身一代以及永久一代。 |
生活 | 堆栈内存仅在当前方法运行时才存在 | 只要应用程序运行,堆空间就存在 |
效率 | 与堆相比,分配速度要快得多 | 与堆栈相比分配速度较慢 |
分配/取消分配 | 分别调用和返回方法时,将自动分配和释放此内存 | 当Gargabe Collector创建新对象并不再引用它们时,将分配堆空间 |
六,结论
堆栈和堆是Java分配内存的两种方式。在本文中,我们了解了它们如何工作以及何时使用它们来开发更好的Java程序。
要了解有关Java中内存管理的更多信息,请在此处查看本文。我们还讨论了JVM垃圾收集器,本文将对此进行简要讨论 。