垃圾收集java
程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭;这几个区域的内存分配和回收都具有稳定性,不须要过多的考虑回收的问题。而Java堆和方法区则不同。算法
Java堆中存储了几乎全部的对象实例,垃圾收集器进行对堆的回收以前,须要判断这些对象是否还存活函数
一。判断对象是否存活线程
判断对象是否还活着,主要有两种方法代理
1.引用计数法对象
给对象添加一个引用计数器,每当一个地方引用时,计数器值加1;内存
每当一个引用失效时,计数器减1;资源
任何计数器为0的对象为不可能被使用的对象。虚拟机
优势:实现简单,断定效率高 效率
缺点:很难解决对象之间的相互循环引用的问题
2.可达性分析法
主流的实现中,都是经过可达性分析法来断定对象是否存活。
该算法基本思想:经过一系列称为“GC Roots”的对象做为起始点,从这些节点开始向下搜索,搜索的路径称为引用链;
当一个对象到GC Roots没有任何引用链相连时(即GC Roots没法到达该对象),称为不可达对象,该对象不可用
此时,能够断定该对象是可回收的对象。
Java中能够做为GC Roots的对象包括如下四种:
(1)虚拟机栈中引用的对象
(2)方法区中类静态属性引用的对象
(3)方法区中常量引用的对象
(4)本地方法栈中JNI(通常说的是Native方法)引用的对象
3.方法区的回收
因为方法区中主要存放的是永久代对象,所以,方法区中进行垃圾收集的性价比通常较低。
永久代的垃圾回收主要分为两类:1.废弃常量 2.无用的类
类的卸载条件比较苛刻,须要同时知足如下三个条件:
(1)该类的全部实例已经被回收,即Java堆中不存在该类的任何实例
(2)加载该类的ClassLoader(即类加载器)已被回收
(3)该类对应的java.lang.Class对象没有在任何地方呗引用,没法在任何地方经过反射访问该类的方法
在大量使用动态代理、反射的场景,须要虚拟机具有卸载类的功能,以保证永久代不会形成内存溢出
4.finalize()
相似 C++ 的析构函数,用于关闭外部资源。
但 try-finally 等方式能够作得更好,而且该方法运行代价很高,不肯定性大,没法保证各个对象的调用顺序,所以最好不要使用。
当一个对象可被回收时,且被断定为有必要执行该对象的 finalize() 方法,那么可能让该对象自救(只须要从新与引用链上的任何一个对象创建关系便可)。
自救只能进行一次,若是回收的对象以前调用了 finalize() 方法自救,后面回收时不会再调用该方法。
二。强引用与软引用
Java对引用的概念分为四种,从强到弱依次为:强引用,软引用,弱引用,虚引用
1.强引用
代码中广泛存在的相似 Object obj = new Object()这种,只要强引用在,该对象永远不会被回收
2.软引用
用来描述一些还有用但非必须的对象;提供了SoftReference类来实现软引用
在系统发生内存溢出异常以前,会把这些对象列入回收范围之中,进行第二次回收
3.弱引用
也是用来描述非必须对象,可是比软引用更弱;提供了WeakReference类来实现
弱引用关联的对象,只能生存到下一次垃圾收集发生以前。
当垃圾收集器工做时,不管当前内存是否足够,都会回收掉只被弱引用关联的对象。
4.虚引用
最弱的引用关系;提供PhantomReference类实现
一个对象是否有虚引用的存在彻底不会对其生存时间产生影响,同时也没法经过虚引用来取得一个对象的实例。
设置虚引用的惟一目的是,经过虚引用在这个对象被回收时收到一个系统通知