1. Java Heap Space
- Java heap空间是java运行时分配内存给对象(OBJECTS)和JRE类的。所有的对象都被创建在堆内存空间上。
- GC 作用于堆内存上释放未被引用的对象的内存。
- 堆内存空间创建的对象能被全局访问,可以在应用的任何地方被引用。
2. Java Stack Memory
- Java栈空间用于线程的执行。
- Stack memory包括短期存活的特定方法值以及方法中对于堆中其他对象的引用。
- 栈内存引用顺序是LIFO(Last in First out)顺序。
- 每当方法被调用时,一个新的内存块在该栈上被创建--用来存放局部基本数据类型值和方法中对于其他对象的引用。
- 方法结束时,方法所在代码块不可用(包括局部基本类型和引用)。
- 栈内存空间相较于堆空间所占内存更小。4. 堆和栈内存在Java 内存模型中的异同
3. 堆栈实例
![](http://cdn.journaldev.com/wp-content/uploads/2014/08/Java-Heap-Stack-Memory.png)
package com.fqyuan.thinking;
public class TestMemory {
public static void main(String[] args) { // Line 1
int i = 1; // Line 2
Object obj = new Object(); // Line 3
TestMemory mem = new TestMemory(); // 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
}
- 当我们一开始运行程序,所有的运行时类被装载在堆空间。在运行到line1的main()方法时,Java Runtime 创建了用于main()方法线程使用的栈内存。
- 在运行到line2时,我们创建了一个基本类型局部变量,所以它被创建并被存储在main()方法的栈内存区域。
- 在运行到line3时,我们创建了一个Object, 该对象的实例被创建在堆内存,在栈内存中包含该实例对象的引用。对于line4亦然,不再赘述。
- 在运行到line5时,我们调用了foo()方法,在当前栈的栈顶将开辟一片内存给foo()方法使用。因为java函数是Pass by value 方式的,所以运行到line6时会有一个新的指向Object对象的引用在foo()的栈空间被创建。
- 运行到line7时,在String Pool中存放着String对象实例,并在foo()的stack空间有其引用。
- 运行到line8时,foo()方法终止,此时栈中分配给foo()的内存块被释放。
- 运行到9时,main()方法终止,分配给main()方法的栈内存被销毁。同时程序也在这一行终止,因而Java Runtime 释放所有的内存,并终止该程序的执行。
4. 堆和栈内存在Java 内存模型中的异同
- 堆内存是被application的所有部分所共用的,而栈内存只被一个执行的线程所使用。
- 不管对象何时被创建,对象实例总是存放在堆内存,而在栈内存存放的是该对象的引用。栈内存中存放的只是基本类型局部变量和堆空间中对象的引用。
- 堆空间中的对象是全局可访问的,而栈内存的数据不能被其他线程访问。
- 栈空间的内存管理是通过LIFO方式完成的,而堆空间的内存管理比其更复杂,因为堆空间的变量是全局可用的。
- 栈空间生命周期是短时存在的,而堆内存生命周期是从开始一直到应用执行的结束。
- 我们可以用-Xms和-Xmx JVM选项来定义堆内存的默认大小和最大值。我们可以用-Xss来定义栈内存空间的大小。
- 当栈内存满时,Java runtime 抛出 java.lang.StackOverFlowError 而当堆内存满时,抛出的java.lang.OutOfMemoryError: Java Heap Space。
- 相较于堆内存而言,栈内存所占空间很小。因为其在内存分配的简洁性(LIFO),栈内存分配相较于堆内存分配而言速度更快。