Java 堆是和 Java 应用程序关系最为密切的内存空间,几乎所有的对象都存放在堆中。并且Java 堆是完全自动化管理的,通过垃圾回收机制,垃圾对象会被自动清理,而不需要显式地释放。
根据垃圾回收机制的不同,Java 堆有可能拥有不同的结构。最为常见的一种构成是将整个Java 堆分为新生代和老年代。其中,新生代存放新生对象或者年龄不大的对象,老年代则存放老年对象。新生代有可能分为 eden 区、s0 区、s1 区,s0 和 s1也被称为 from 和to 区域,它们是两块大小相等、可以互换角色的内存空间。
下图显示了一个堆空间的一般结构:
在绝大多数情况下,对象首先分配在 eden 区,在一次新生代回收后,如果对象还存活,则会进入 s0 或者 s1,之后,每经过一次新生代回收,对象如果存活,它的年龄就会加 1。当对象的年龄达到一定条件后,就会被认为是老年对象,从而进入老年代。
下面通过一个简单的示例,来展示 Java 堆、方法区和 Java 栈之间的关系。
package test;
public class TestHeap {
private int id;
public TestHeap(int id){
this.id = id;
}
public void show(){
System.out.println("我的id是"+id);
}
public static void main(String[] args) {
TestHeap t1 = new TestHeap(1);
TestHeap t2 = new TestHeap(2);
t1.show();
t2.show();
}
}
上述代码声明了一个 TestHeap 类,并在 main()函数中创建了两个 TestHeap 实例。此时, 各对象和局部变量的存放如下图所示。 TestHeap 实例本身分配在堆中, 描述 TestHeap 类的信息存放在方法区,main()函数中 t1 和 t2 局部变量存放在 Java 栈中,并指向堆中的两个实例。