堆和栈都是Java在Ram中存放数据的地方,Java自动管理堆和栈,开发者不能直接地设置堆或栈。
Java的堆是一个运行时数据区,类的对象从中分配空间。这些对象通过 new 等指令建立,它们不需要程序代码来显式的释放。堆是垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存,因此用堆保存数据时会得到更大的灵活性。变量所需的存储空间只有在运行时创建了对象之后才能确定。Java的垃圾回收器会自动回收这些不再使用的数据,缺点是由于要在运行时动态分配内存,存取速度较慢。
Java的栈主要存放一些基本类型的变量(byte、int、short、long、float、double、boolean、char)和引用对象,栈里存的是堆的首地址,就像引用对象。栈的优势是,存取速度比堆快,仅此于寄存器,栈数据可以共享。但缺点是存在栈的数据大小与生存期必须是确定的,缺乏灵活性。
Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在栈中分配的内存只是一个指向这个堆对象的指针(引用变量)而已。
在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。
引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其他作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用new产生数组或对象的语句所在的代码块外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它时,才变成垃圾,不能再被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器是释放掉。如:
String s = new String("abc");
这变量s存放在栈里,而"abc"这个对象存放在堆里面。s指向"abc";
就对象本身而言,它的所有属性的值如果不是单例或者静态的,就是存储在堆里面。一个的所有对象的属性值都在堆里面并且占用不同的内存空间,而一个类的方法只在方法区里占一个地方。
栈有一个重要特性:存在栈中的数据可以共享。
注:
- 使用诸如String str = "abc";的格式定义类时,对象可能并没有被创建!而可能只是指向一个先前已经创建的对象。
- 只有通过new()方法才能保证每次都创建一个新的对象。