垃圾收集器回收对象的依据和时机

-----------------------------------------------------------------------
垃圾收集器回收对象的依据、时机等问题
-----------------------------------------------------------------------		
Java中的引用:
	Java中将引用分为强引用、软引用、弱引用、虚引用4种,强度依次减弱。
	强引用:Object obj = new Object(),只要强引用还存在,垃圾收集器就永远不会回收这些引用关联着的对象。
	软引用:用来描述一些还有用但并非必需的对象。
		在系统将要发生内存溢出异常前,垃圾收集器才会去回收这些软引用关联着的对象。jdk1.2之后,提供了SoftReference类来实现软引用。
	弱引用:和软引用一样,也是描述一些还有用但并非必须的对象,只是它的强度更弱一些。
		当垃圾收集器工作时,无论当前内存是否够用,都会回收掉只被弱引用关联的对象。jdk1.2之后,提供了WeakReference类来实现软引用。
	虚引用:是最弱的一种引用,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。
		设置虚引用的唯一目的:在这个对象被垃圾收集器回收时得到一个系统通知。
		

判断对象是否存活的算法:
	1)引用计数算法:
		概念:给对象添加一个引用计数器,每当有一个地方引用它时,计数器就加1;当引用失效时,计数器就减1;当计数器为0时,对象就不能再使用了。
		说明:Java虚拟机里面没有采用 引用计数算法 来管理内存。原因:不能解决对象之间相互循环引用的问题
		案例:
			ReferenceCountingGC{
			
				public Object instance = null;
				
				// 这个成员属性的唯一意义就是占用一些内存,以便在GC日志中可以明显地看出是否被回收过
				private byte[] bigBlock = new byte[1024 * 1024];
				
				public static void testGC() {
					ReferenceCountingGC objA = new ReferenceCountingGC();
					ReferenceCountingGC bojB = new ReferenceCountingGC();
					
					objA.instance = objB;
					objB.instance = objA;
					
					objA = null;
					objB = null;
					
					// 假设在这行发生GC,那么objA和objB是否被回收呢?
					System.gc();
				}
			}
			
			由运行结果可以看出:虚拟机并没有因为这两个对象相互引用就不去回收它们。说明:虚拟机不是通过引用计数算法来判断对象是否是存活的。

	2)可达性分析算法(根搜索算法):
		概念:从根节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象与根节点之间不存在任何引用链时,则证明此对象是不可用的。
		根对象的判定:
			1)虚拟机栈(栈帧中的本地变量表)中引用的对象、本地方法栈中JNI(即native方法)引用的对象。
			2)方法区中:类静态属性引用的对象、常量引用的对象。

	
			
一个对象被回收要经过两次标记:	

	第一次标记:
		如果一个对象在进行可达性分析后没有发现与根对象间存在引用链,那么这个对象将被第一次标记,并进行判断:判断此对象是否有必要去执行finalize()方法。
			1)如果:对象没有覆盖finalize()方法,或者finalize()方法已经被调用过了,虚拟机就不会执行该对象的finalize()方法,直接回收该对象。
			
			2)如果:对象覆盖了finalize()方法,并且finalize()方法没有被调用过,那么:
			
				1>这个对象将会放置在一个叫做F-Queue 的队列中,稍后(在第二次标记之前),会有一个由虚拟机自动建立的、低优先级的Finalizer线程去执行该对象的finalize()方法。
				2>注意:这里的“执行”是指虚拟机会触发这个方法,但是并不保证会等待这个方法运行结束。原因:如果某个对象执行finalize()方法花费的时间比较长,或者发生了死循环,这样的话就很可能会导致F-Queue队列中其它的对象永久等待,如果JVM要等待它运行结束,则有可能会导致整个内存回收系统崩溃。

				
	第二次标记:
		1)在第一次标记后,GC将对 F-Queue 中的对象进行第二次标记,如果对象在finalize()方法中成功拯救自己,那么这个对象将被移出”即将回收“的那个集合。
		2)如果没有在finalize()方法中救出自己,那么它将被GC回收。
			注:在finalize()方法中拯救自己的方法:只要重新与引用链上的任何一个对象建立关联即可。例如:将自己(this)赋值给某个对象的成员变量。
		


			

猜你喜欢

转载自blog.csdn.net/A__17/article/details/49702137