不久前我写了几篇关于Java 垃圾收集 and Java 是按值传递。之后我收到了很多电子邮件来解释Java堆空间, Java堆栈内存, Java中的内存分配它们之间有什么区别?您会在 Java、Java EE 书籍和教程中看到很多对堆和堆栈内存的参考,但几乎没有从程序的角度完整解释什么是堆和堆栈内存。
Java 运行时使用 Java 堆空间为对象和 JRE 类分配内存。每当我们创建一个对象时,它总是在堆空间中创建。垃圾收集在堆内存上运行,以释放没有任何引用的对象使用的内存。在堆空间中创建的任何对象都具有全局访问权限,并且可以从应用程序的任何位置引用。
Java 堆栈内存用于执行线程。它们包含特定于方法的短暂值以及对堆中从该方法引用的其他对象的引用。堆栈内存始终按 LIFO(后进先出)顺序引用。每当调用一个方法时,都会在堆栈内存中创建一个新块,以便该方法保存本地原始值并引用该方法中的其他对象。一旦该方法结束,该块就会变得未使用并可用于下一个方法。与堆内存相比,堆栈内存大小非常小。
让我们通过一个简单的程序来了解堆和堆栈内存的使用情况。
package com.journaldev.test;
public class Memory {
public static void main(String[] args) { // Line 1
int i=1; // Line 2
Object obj = new Object(); // Line 3
Memory mem = new Memory(); // Line 4
mem.foo(obj); // Line 5
} // Line 9
private void foo(Object param) { // Line 6
String str = param.toString(); //// Line 7
System.out.println(str);
} // Line 8
}
The below image shows the Stack and Heap memory with reference to the above program and how they are being used to store primitive, Objects and reference variables. Let’s go through the steps of the execution of the program.
- 一旦我们运行程序,它就会将所有运行时类加载到堆空间中。当在第 1 行找到 main() 方法时,Java 运行时会创建供 main() 方法线程使用的堆栈内存。
- 我们在第 2 行创建原始局部变量,因此它被创建并存储在 main() 方法的堆栈内存中。
- 由于我们在第三行创建一个对象,因此它是在堆内存中创建的,而堆栈内存包含它的引用。当我们在第 4 行创建 Memory 对象时,会发生类似的过程。
- 现在,当我们在第 5 行调用 foo() 方法时,会在堆栈顶部创建一个块以供 foo() 方法使用。由于 Java 是按值传递的,因此在第 6 行的 foo() 堆栈块中创建了对 Object 的新引用。
- 第 7 行创建了一个字符串,它进入字符串池在堆空间中,并在 foo() 堆栈空间中为其创建一个引用。
- foo()方法在第8行终止,此时栈中为foo()分配的内存块变得空闲。
- 在第 9 行,main() 方法终止,为 main() 方法创建的堆栈内存被销毁。此外,程序在这一行结束,因此 Java 运行时释放所有内存并结束程序的执行。
根据上面的解释,我们可以很容易地得出堆内存和栈内存的以下区别。
- 堆内存由应用程序的所有部分使用,而堆栈内存仅由一个执行线程使用。
- 每当创建一个对象时,它总是存储在堆空间中,并且堆栈内存包含对其的引用。堆栈内存仅包含局部原始变量和堆空间中对象的引用变量。
- 存储在堆中的对象可以全局访问,而堆栈内存不能被其他线程访问。
- 堆栈中的内存管理以 LIFO 方式完成,而堆内存中的内存管理更复杂,因为它是全局使用的。堆内存分为Young-Generation、Old-Generation等,更多详细信息请参见Java 垃圾收集.
- 堆栈内存是短暂的,而堆内存从应用程序执行开始到结束都存在。
- 我们可以用-Xms and -XmxJVM选项定义堆内存的启动大小和最大大小。我们可以用-Xss定义堆栈内存大小。
- 当堆栈内存已满时,Java运行时会抛出异常
java.lang.StackOverFlowError
而如果堆内存已满,则会抛出java.lang.OutOfMemoryError: Java Heap Space
error.
- 与堆内存相比,堆栈内存大小非常小。由于内存分配 (LIFO) 简单,因此与堆内存相比,堆栈内存非常快。
这就是全部Java 堆空间与堆栈内存就java应用程序而言,我希望它能消除您对执行任何java程序时的内存分配的疑虑。
参考:https://en.wikipedia.org/wiki/Java_memory_model.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)