Java内存区域与Java垃圾回收

阐述Java内存区域与Java回收机制的关联

原文地址
JavaGC与内存区域


Java内存区域

1.JVM管理的内存区域

1.程序计数器

程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行。(线程私有)不存在内存溢出的情况,是JVM中唯一一个没有定义OOM的区域。
线程私有

2.JVM Stack 虚拟机栈

一个线程每个方法执行的同时,都会创建一个栈帧(Stack Frame),栈帧中存储局部变量表,操作站,动态链接,方法出口等,当方法被调用时,栈帧在JVM中入栈,当方法执行完成,栈帧出栈。
局部变量表中存储着方法相关局部变量,包括基本数据类型,对象的引用,返回地址等。Java虚拟机允许动态扩展栈的大小,所以线程一直申请栈,知道内存不足,抛出OOM。
每个线程对应一个JVM Stack,所以也是线程私有。

3.Native Method Stack 本地方法栈

本地方法栈在作用,运行机制,异常类型等方面都与虚拟机栈相同,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。
本地方法栈也是线程私有的。

4.Heap 堆区

Heap 是Java GC机制最重要的区域,没有之一。在JVM管理的内存中,堆区是最大的一块,堆区也是Java GC机制所管理的主要区域。堆区所有线程共享,在虚拟机启动时创建。堆区的纯在是为了存储对象实例
堆内存需要在逻辑上是连续的,物理上不需要,并且可扩展,如果在执行垃圾回收之后仍没有足够内存分配就会OOM。

5.Method Area 方法区

方法区并不是堆区。
方法区是各个线程共享的,用于存储已经被虚拟机加载的类信息(加载类的信息,方法、接口、field等),final常量,静态变量等
方法区可以选择性做GC,一般方法区上执行GC很少,因此常被称为永久代。也会抛出OOM。


Java的对象访问方式

一般来说,一个Java对象的引用访问涉及到3个区域内存区域:JVM栈, 堆区,方法区

Object object = new Object()

Object object表示一个本地引用,存储在JVM栈的本地变量表中,表示一个reference类型数据 new Object()表示作为实例存储在堆中
*堆中的实例还记录了Object类型信息的地址,指向方法区中存储的类的信息

目前有两种主流访问方式
1.通过句柄访问

通过句柄访问的实现方式中,JVM堆中会专门有一块区域用来作为句柄池,存储相关句柄所执行的实例数据地址(包括在堆中地址和在方法区中的地址)。这种实现方法由于用句柄表示地址,因此十分稳定。

2.通过直接指针访问

通过直接指针访问的方式中,reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。这种方法最大的优势是速度快,在HotSpot虚拟机中用的就是这种方式。