`
robinjoe
  • 浏览: 44927 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【转】Java高级进阶学习-Java的内存回收(3)

阅读更多

(3)弱引用
  弱引用与软引用有点相似,区别在于弱引用所引用对象的生存期更短。弱引用通过WeakReference类实现,弱引用和软引用很像,但弱引用的引用级别更低。对于只有弱引用的对象而言,当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存。当然,并不是说当一个对象只有弱引用时,它就会立即被回收,正如那些失去引用的对象一样,必须等到系统垃圾回收机制运行时才会被回收.

下面程序示范了弱引用所引用对象也会被系统垃圾回收的过程.
import java.lang.ref.*;
import java.util.*;
public class WeakReferenceTest
{
public static void main(String[] args) throws Exception
{
//创建一个字符串对象
String str = new String("网络时空");
//创建一个弱引用,让此弱引用引用到"网络时空"字符串
WeakReference<String> wr = new WeakReference<String>(str); //①
//切断str引用和"网络时空"字符串之间的引用
str = null; //②
//取出弱引用所引用的对象
System.out.println(wr.get()); //③

List<String> list=new ArrayList<String>();
list.add(wr.get());

//强制垃圾回收
System.gc();
System.runFinalization();
//再次取出弱引用所引用的对象
System.out.println(wr.get()); //④
}
}

运行结果如下

Java高级进阶学习-Java的内存回收(3)

 

说明如下
上面程序创建了一个“网络时空”的字符串对象,并让str引用变量引用它。执行①行处代码时,系统创建了一个弱引用对象,并让该对象和str引用同一个对象。当程序执行到②行代码时,切断了str和"网络时空"字符串对象之间的引用关系,此时系统图如下所示
内存中分布效果图如下

Java高级进阶学习-Java的内存回收(3)


  从此内存中图示可以看出,此时“网络时空”字符串对象只有一个弱引用对象引用它,程序依然可以通过这个弱引用对象来访问字符串常量,程序中③行代码依然输出“网络时空”,接下来程序强制垃圾回收,如果系统垃圾回收机制启动,只有弱引用的对象就会被清理掉。当程序执行④行代码时,通常就会看到输出null,这表明该对象已经被清理掉了

总结说明:

1.弱引用具有很大的不确定性,因为每次垃圾回收机制执行时都会回收弱引用所引用的对象,而垃圾回收机制的运行又不受程序员的控制,因此程序获取弱引用所引用的java对象时必须小心空指针异常,通过弱引用所获取的java对象可能是null

2.由于垃圾回收的不确定性,当程序希望从弱引用中取出被引用对象时,可能这个被引用对象已经被释放了。如果程序需要使用被引用的对象,则必须重新创建该对象,这个可能可以采用如下风格的代码完成。

伪码形式表示如下

//取出弱引用所引用的对象

obj=wr.get();

//如果取出的对象为null

if(obj==null)

{

  //重新创建一个新的对象,将其使用强引用来引用它

obj=recreateIt();

//取出弱引用所引用的对象,将其赋给wr变量

wr=new WeakReference(obj);

}

...//操作obj对象

//再次切断obj和对象之间的关联

obj=null;

 

 

(4)虚引用
  软引用和弱引用可以单独使用,但虚引用不能单独使用,单独使用虚引用没有太大的意义。虚引用的主要作用就是跟踪对象被垃圾回收的状态,程序可以通过检查虚引用关联的引用队列中是否包含指定的虚引用,从而了解虚引用所引用的对象是否将被回收.
  引用队列由java.lang.ref.ReferenceQueue类表示,它用于保存被回收对象的引用。当把软引用,弱引用和引用队列联合使用时,系统回收被
引用的对象之后,将会把被回收对象对应的引用添加到关联的引用队列中。与软引用和弱引用不同的是,虚引用在对象被释放之前,将把它对应的虚引用添加到关联的队列中,这使得可以在对象被回收之前采取行动。
虚引用通过PhantomReference类实现,它完全类似于没有引用。虚引用对对象本身没有大的影响,对象甚至感觉不到虚引用的存在。如果一个
对象只有一个虚引用,那它和没有引用的效果大致相同。虚引用主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和队列ReferenceQueue联合使用.

  下面程序与上面程序基本类似,只是使用了虚引用来引用字符串对象,虚引用无法获取它引用的对象,下面程序还将和引用队列结合使用,可以看到,被虚引用所引用对象被垃圾回收后,虚引用将被添加到引用队列中。

import java.lang.ref.*;
public class PhantomReferenceTest
{
public static void main(String[] args)
throws Exception
{
//创建一个字符串对象
String str = new String("网络时空");
//创建一个引用队列
ReferenceQueue<String> rq = new ReferenceQueue<String>();
//创建一个虚引用,让此虚引用引用到"网络时空"字符串
PhantomReference<String> pr =
new PhantomReference<String>(str , rq);
//切断str引用和"网络时空"字符串之间的引用
str = null;
//试图取出虚引用所引用的对象,
//程序并不能通过虚引用访问被引用的对象,所以此处输出null
System.out.println(pr.get()); //①
//强制垃圾回收
System.gc();
System.runFinalization();
//取出引用队列中最先进入队列中引用与pr进行比较
System.out.println(rq.poll() == pr); //②
}
}

Java高级进阶学习-Java的内存回收(3)

 

  因为系统无法通过虚引用来获得被引用的对象,所以执行①处的输出语句,程序将输出null(即使此时未进行强制垃圾回收)。当程序强制垃圾回收后,只有虚引用引用的字符串对象将会被垃圾回收,当被引用的对象被回收后,对应引用将被添加到关联的引用队列中,因而将在②处代码处看到输出true.

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics