Java堆内存(Heap Memory)
堆内存在Java运行时主要去回收对象和JRE的类。当我们创建了一个对象(也就是 new一个对象时),在堆内存就会为对象分配一个空间,Java垃圾回收器(GC)运行在堆内存里,一旦发现没有任何地方引用到这个对象,就释放这个对象所占的内存。
被创建的对象存在于堆内存,并且拥有全局权限,能被应用程序的任何地方引用到。
Java栈内存(Stack Memory)
栈内存是单线程执行的,它的空间比堆内存空间要小。它里面会包括定义在方法里的、短时间存在的局部变量,这些局部变量总是引用到堆内存的对象。栈内存还有个特点就是后进先出。当一个方法被调用之后,在栈内存就会为这个方法产生一个内存区域来保存方法里的基本数据类型数据和引用了堆内存中对象的局部变量。当这个方法执行完毕,这个块没有用了,就会被垃圾回收器回收,接着继续下一个方法。
加深理解
先来看一段简单的代码
public class TestMemory {
public static void main(String[] args) {
int i = 666; //line1
Object object = new Object(); //line2
TestMemory testMemory = new TestMemory();//line3
testMemory.test(object); //line4
}
//line5
private void test(Object params){ //line6
String str = params.toString(); //line7
System.out.println(str); //line8
}
}
//line9
下面这张图片展示了上面代码的内存信息。
- 当程序运行时,JVM会先加载运行时类和我们自己写的类信息,这些类信息加载后存在于堆内存当中。
- 接着进入到main方法,第一行line1创建了一个基本数据类型i=666,所以创建了一个main方法的内存块,它里面同时存放了i=666;
- 接着执行line2和line3的位置
Object object = new Object();
TestMemory testMemory = new TestMemory();
创建了两个局部变量,object和testMemory,同时在堆里存放了两个新的对象Object和TestMemory。(每次我们new 一个对象都会在堆区产生一块内存区给它分配空间)。同时object和testMemory引用了new出来的对象。 - 现在到了line4,test方法了,当调用到test方法的时候,在栈的顶层创建了一块test()方法的内存区(我们说过栈的特点就是后进先出),由于在 Java里的传递是值传递,所以就有了参数object产生了一个新的引用。
- 最后调用了toString产生了一个字符串常量存放在了String pool里,并且str 引用了它。(如果你对String类感兴趣,你可能喜欢 《 Java学习笔记–String类》)
- 当test方法结束,它里面的变量也就被GC回收掉了。接着main方法也就结束。Java在运行时释放这些内存并结束程序的运行。
总结
- 当一个对象被创建,总是会在堆内存为它分配空间并且存储,如果有赋值就会将变量引用到对象。而栈内存就是存放这些引用对象的局部变量。
- 栈内存的生命周期很短,而堆内存从程序执行开始到结束一直都在工作。栈内存中每当执行完一个方法,它们所占的内存区就会被释放。而堆内存里的对象只有在没有任何变量引用到它的时候才可能会被释放。
- 栈内存大小相比于堆内存非常小。但是它相对于堆内存却比较快。