Java中强引用、软引用、弱引用、虚引用内容解析------夜空中最亮的星

很高兴能写下这篇博客,因为这是对我学习新知识的总结,更重要的是可以同大家一起分享知识,畅游在知识的海洋。
欢迎留言,我会定时查阅留言,及时答复并改正博客的不足,请多包容,谢谢!你们也要多注意身体健康!
再苦再累,我不会放弃,因为夜空中最亮的星是我的梦。
谈到强引用(StrongReference)、软引用(SoftReference),弱引用(WeakReference)、虚引用(PhantomReference),会涉及到垃圾回收器机制GC。
什么是GC(全称:GabageCollection)?
GC通常是运行在一个独立的、优先级比较低的线程中,实时监测并释放“无效”的内存。
什么是“无效"的内存单元?
一般GC采用引用计数法来判断一个内存单元(一个变量)是否是无效的内存。
引用计数法(引用计数法只是GC中一种常用的方法,还会用到年代方法等)是指一个变量或一块内存当前被引用的次数,如果引用次数为0,则表示这个变量或这块内存未被引用,因此GC“有可能”去释放它 ,为什么说有可能?首先GC运行在一个独立的、优先级比较低的线程中,其次GC回收的具体工作也是比较复杂的,比如说需要释放大量内存的时候,而CPU资源又相对紧张,GC可能会选择性 的释放一些内存资源,具体回收方法取决于GC内部的算法。
一个占用内存较大的对象、或者一个存储图片的对象,他们有时无用、又占用大量内存资源而GC又没有办法去释放,从而造成严重后果。一般原则是:对占用大量内存的变量使用完后主动将其置为NULL,可能的话主动调用一次GC回收机制:System.gc(), 特别是一些static型的引用风险很大。

  /**
	*大概译文:调用System.gc()方法时,会指示虚拟机去运行垃圾回收器,但这仅是一个提示作用,不会保证虚拟机实际运行
	* Indicates to the VM that it would be a good time to run the
	* garbage collector. Note that this is a hint only. There is no guarantee
	* that the garbage collector will actually be run.
     */
    public static void gc() {
        boolean shouldRunGC;
        synchronized(lock) {
            shouldRunGC = justRanFinalization;
            if (shouldRunGC) {
                justRanFinalization = false;
            } else {
                runGC = true;
            }
        }
        if (shouldRunGC) {
            Runtime.getRuntime().gc();
        }
    }

1.强引用 StrongReference

强引用是使用最普遍的引用,如果一个对象具有强引用,垃圾回收器不会回收它。只有当其他对象没有对这个对象强引用时,才可能被GC回收掉。否则当内存空间不足

,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会回收强引用的对象。
/**
	 * 测试强引用
	 */
	public void testStrongReference(){
		System.out.println("\n***************强引用********************\n");
		String strongStr = new String("强引用"); //强引用,永远不会被gc回收,即使程序因OutOfMemory而崩溃
		strongStr = null; //取消强引用,内存不足时,有可能被gc回收,因为gc处在的线程中优先级比较低
		System.gc();		
	}

2.软引用 SoftReference:


如果一个对象具有软引用,当内存空间足够,垃圾回收器就不会回收它,当内存空间不足了,就可能回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以


被程序使用,软引用可用来实现内存敏感的高速缓存。一般对于这种占用内存资源比较大的,又不是必要的变量,或者一些占用大量内存资源的一些缓存的变量,就需要考虑


用SoftReference。
/**
	 * 测试软引用
	 */
	public void testSoftReference(){
		System.out.println("\n***************软引用********************\n");
		String softStr = new String("软引用");
		ReferenceQueue softQueue = new ReferenceQueue();
		//如果gc预回收软引用,在回收前将该引用对象加入到ReferenceQueue中 
		SoftReference<String> softRef = new SoftReference<String>(softStr,softQueue);
		softStr = null; //取消强引用
		System.out.println("软引用...gc回收前...str = "+softRef.get());
		System.gc();
		if(softRef.get() == null){
			System.out.println("软引用...利用SoftReference判断...内存不足...gc已回收软引用...str = "+softRef.get());	
		}else{
			System.out.println("软引用...利用SoftReference判断...内存充足...gc未回收软引用...");
		}
		
		Reference softPollRef = (Reference)softQueue.poll();
		if(softPollRef != null){			
			System.out.println("软引用...利用ReferenceQueue判断...内存不足...gc已回收软引用...str = "+softPollRef.get());
		}else{
			System.out.println("软引用...利用ReferenceQueue判断...内存充足...gc未回收软引用...");
		}
		
		/**
		 * 内存充足结果:
		 	软引用...gc回收前...str = 软引用
			软引用...利用SoftReference判断...内存充足...gc未回收软引用...
			软引用...利用ReferenceQueue判断...内存充足...gc未回收软引用...
		 */
		
	}

3. 弱引用 WeakReference


弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。如果一个对象只具有弱引用,只要垃圾回收器在内存空间检测到了,不管当前内存空间足够


与否,都会回收对应的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
/**
	 * 测试弱引用
	 */
	public void testWeakReference(){
		System.out.println("\n***************弱引用********************\n");
//		String weakStr = null; //弱引用,空值不会被加入到ReferenceQueue中		
		String weakStr = new String("弱引用"); //强引用创建新的string类型数据
		
		//只有该引用对象被gc回收后,才会添加到(但不是一定)ReferenceQueue中,但被gc回收后,有时queue.poll中又没有数据
		ReferenceQueue weakQueue = new ReferenceQueue();
		WeakReference<String> weakReference = new WeakReference<String>(weakStr,weakQueue);		
		weakStr = null; //取消强引用,gc才会回收弱引用对象
		System.out.println("弱引用...利用WeakReference判断...gc回收前...weakStr = "+weakReference.get());	
		System.gc();
		System.out.println("弱引用...利用WeakReference判断...gc回收后...weakStr = "+weakReference.get());
		/**		
		 * 
		 * 原文:(地址:Java? Platform Standard Ed. 6----http://docs.oracle.com/javase/6/docs/api/)
		 * Polls this queue to see if a reference object is available. 
		 * If one is available without further delay then it is removed 
		 * from the queue and returned. Otherwise this method immediately returns null.
		 * 
		 * 译文:
		 * 轮询此队列,查看引用对象是否可获得的。
		 * 如果一个引用对象是可获得的,并且没有进一步的延迟,
		 * 然后它会被从队列中移除和返回。
		 * 如果该引用对象发生延迟,这个方法立即返回null
		 * 
		 *结论:
		 *通过译文可以看到,如果对列中可获得的引用没有进一步延迟,该引用对象会被立即返回,
		 *如果有延迟发生,这个方法立即返回null。所以reference有时等于null,有时不为null,
		 *所以也就会出现以下注释的两种结果(结果1,结果2)
		 *
		 *要出现以下语意的结果,前提必须调用System.gc(),且该引用对象已取消强引用
		 */
		Reference weakPollRef = (Reference)weakQueue.poll();
		if(weakPollRef != null){
			System.out.println("弱引用...利用ReferenceQueue判断...gc已回收弱引用...queue中的值 = "+weakPollRef.get());	
		}else{
			System.out.println("弱引用...利用ReferenceQueue判断...gc已回收弱引用......获得对列中的引用对象发生延迟...");
		}
		
		/*
		  结果1:
		  		弱引用...利用WeakReference判断...gc回收前...weakStr = 弱引用
				弱引用...利用WeakReference判断...gc回收后...weakStr = null
				弱引用...利用ReferenceQueue判断...gc已回收弱引用......获得对列中的引用对象发生延迟...
		 结果2:
		    	弱引用...利用WeakReference判断...gc回收前...weakStr = 弱引用
				弱引用...利用WeakReference判断...gc回收后...weakStr = null
				弱引用...利用ReferenceQueue判断...gc已回收弱引用...queue中的值 = null


		 */
				
	}

4.虚引用 PhantomReference


如果一个对象只具有虚引用,那么它就和没有任何引用一样,随时会被jvm当作垃圾进行回收,虚引用主要是用于跟踪一个对象何时被GC回收。

/**
	 * 测试虚引用
	 */
	public void testPhantomReference(){		
		System.out.println("\n***************虚引用********************\n");
		String phantomStr = new String("虚引用测试");
		ReferenceQueue phantomQueue = new ReferenceQueue(); 
		PhantomReference<String> phantomReference = new PhantomReference<String>(phantomStr, phantomQueue);
		phantomStr = null; //取消强引用
		/**
		 * 有关phantomReference.get()的说明:
		 * 
		 * 原文:
		 * Returns {@code null}.  The referent of a phantom reference is not
		 *  accessible.
		 *  
		 * 译文:
		 * phantomReference.get()返回空值,虚引用的引用对象是不可获得的
		 * 
		 * 结论:
		 *与译文可知,phantomReference.get()方法始终返回空值
		 */
		System.out.println("虚引用....利用PhantomReference...gc回收前...phantomStr = "+phantomReference.get());
		System.gc();
		System.out.println("虚引用....利用PhantomReference...gc回收后...phantomStr = "+phantomReference.get());
		
		/**
		 * 同软引用一样,会出现两种结果,请详细查看软引用说明
		 * 要出现以下语意的结果,前提必须调用System.gc(),且该引用对象已取消强引用
		 */
		Reference phantomPollRef = phantomQueue.poll();
		if(phantomPollRef != null){
			System.out.println("虚引用....利用ReferenceQueue...gc已回收...phantomStr = "+phantomPollRef.get());
		}else{
			System.out.println("虚引用....利用ReferenceQueue...gc已回收虚引用......获得对列中的引用对象发生延迟......");
		}
		
		/**
		 * 结果1:
			虚引用....利用PhantomReference...gc回收前...phantomStr = null
			虚引用....利用PhantomReference...gc回收后...phantomStr = null
			虚引用....利用ReferenceQueue...gc已回收...phantomStr = null
		 *结果2:
		 	虚引用....利用PhantomReference...gc回收前...phantomStr = null
			虚引用....利用PhantomReference...gc回收后...phantomStr = null
			虚引用....利用ReferenceQueue...gc已回收虚引用......获得对列中的引用对象发生延迟......
		 */
	}


                
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值