概述:Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭,因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就随着回收了。而java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间时才能知道会创建哪些对象,这部分内存的分分配和回收都是动态的,该机收集器所关注的是这部分内存。
对象已死吗?
很多教科书判断对象是否存货的算法是这样的:给对象中添加一个引用计时器,每当有一个地方引用它时,计数器的值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。客观的说,引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例。但是,至少主流的Java虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。
可达性分析算法,在主流的商用程序语言的主流实现中,都是通过可达性分析(Reachability Analysis)来判定对象是否存活着。这个算法的基本思路就是同一个一系列的成为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何应用链相连,则证明此对象不可用的。如下图所示,对象object5、object6、object7虽然相互有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。
在Java语言 中,可作为GC Roots的对象包括下面几种:
1.虚拟机栈(栈帧中的本地变量表)中引用的对象
2.方法区中类静态属性引用的对象
3.方法去中常量引用的对象
4.本地方法栈中JNI(即一般说的Native方法)引用对象
再谈引用
无论是通过引用计数器算法判断对象引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判断对象是否存活都与“引用”相关。在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种,引用强度依次减弱。
1.强引用就是指在程序代码中普遍存在的,类似“Object obj=new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
2.软引用是用来描述一些还有用但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收没有足够的内存,才会抛出内存溢出异常。
3.弱引用也是用来描述非必需对象的,但是他的强度比软引用更弱一点,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
4.虚引用也成为幽灵引用,它时最弱的引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。
Nani