基础
Java内存区域
要想深入的了解java虚拟机,我们必须先对它的内存分布做一个大概的了解,如下是一张虚拟机内存分布图。

方法区
用于存储运行时常量池、已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
堆内存
堆区是Java虚拟机所管理的内存中最大的一块,主要存储对象的实例。
虚拟机栈
生命周期与线程是同步的,每个方法在执行的同时,都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出入口等信息,每个方法的调用到执行完成的过程就是一个栈帧入栈到出栈的过程。
本地方法栈
与虚拟机栈执行的基本相同,唯一的区别就是虚拟机栈是执行Java方法的,本地方法栈是执行native方法的。
程序计数器
是一块较小的内存空间,用来指定当前线程执行字节码的行数,每个线程计数器都是私有的,因为每个线程都需要记录执行的行数 ,如果线程执行是一个Java方法的时候,计数器记录的是虚拟机字节码指令的地址;当执行的是Native的方法的时候,计数器指令为空;该内存区域是Java虚拟机唯一没有规定任何OutOfMemoryError的区域。
垃圾回收
存活算法
引用计数法
java并不采用这种方式进行对象存活判断。在堆中存储对象时,在对象头处维护一个counter计数器,如果一个对象增加了一个引用与之相连,则将counter++。如果一个引用关系失效则counter–。如果一个对象的counter变为0,则说明该对象已经被废弃,不处于存活状态。 如果一个对象A持有对象B,而对象B也持有一个对象A,会使得GC永远无法回收这两个对象。
可达性分析法
通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。

如上图所示,Obj1~Obj4对GC Roots都是可达的,说明不可被回收,Obj5和Obj7对GC Roots节点不可达,说明其可以被回收。那么什么可以当做GC Roots呢?
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(即一般说的Native方法)引用的对象
垃圾回收算法
标记-清除法
最基础的垃圾回收算法,分为两个阶段,标注和清除。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。

从图3中我们可以看到这个回收算法有一个很大的缺点,那就是内存利用不连续,被碎片化了,会导致以后大对象无法找到可利用的空间。
复制法
为了解决Mark-Sweep算法内存碎片化的缺陷而被提出的算法。按内存容量将内存划分为等大小的两块。每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另一块上去,把已使用的内存清掉。

标记-整理法
结合了以上两个算法,为了避免缺陷而提出。标记阶段和Mark-Sweep(标记-清除)算法相同,标记后不是清理对象,而是将存活对象移向内存的一端。然后清除端边界外的对象。

分代收集法
垃圾收集器
Last updated