引用类型
在java中提供了四个级别的引用,分别是强引用,软引用,弱引用,虚引用。在这四种引用级别中,只有强引用FinalReference类是包内可见的,其它三种引用类型,均为public。可以在应用程序内直接使用。
强引用
通过引用可以对堆中的对象进行操作,在某函数中,当创建了一个对象,该对象被分配在堆中,通过这个对象的引用,才能对这个对象进行操作。
StringBuffer sb=new StringBuffer(“Hello World”);
假设以上代码是在函数体运行的,那么局部变量sb被分配到栈上,而对象StringBuffer的实例,被分配到堆上,局部变量str指向StringBuffer实例所在的堆空间。通过sb可以操作该实例,那么str就是StringBuffer的引用。
如果运行一个赋值语句:
StringBuffer str=sb;
那么sb所指向的对象也将被str所指向,同时在局部栈空间上,会分配空间存放str这个引用变量,此时,实例StringBuffer就有两个引用。“==”操作符这时的意义就是表示两个操作数所指向堆空间的地址是否相同,不表示两个操作数所指向的对象是否相等。
两个引用都是强引用,强引用具备以下特点:
- 强引用可以直接访问目标对象。
- 强引用所指向的对象在任何时候都不会被系统回收,JVM宁愿抛出OOM异常。也不回收强引用所指的对象。
- 强引用可能导致内存泄漏。
软引用
软引用是除了强引用外,最强的引用类型,一个持有软引用的对象,不会被JVM很快回收,JVM会根据当前堆的使用情况判断何时回收,当堆使用率临近阈值时,才会去回收软引用对象。只要有足够的内存,软引用便可能在内存中存活相当长的一段时间,因此,软引用可以实现对内存敏感的Cache。
软引用用法:
SoftReference<String> sr=new SoftReference<String>(new String("hello"));
System.out.println(sr.get());
//sr.get()是调用强引用
当系统内存不足的时候软引用就会被回收
弱引用
弱引用是一种比软引用弱的引用类型,在系统GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收,但是由于垃圾回收器的线程优先级很低,因此,并不一定很快发现有弱引用对象,在这种情况下弱引用对象可以存在较长的时间,一旦一个弱引用对象被垃圾回收器回收,便会加入到一个注册引用队列中。
WeakReference<String> wr=new WeakReference<String>(new String("aa"));
System.out.println(wr.get());
System.gc();
System.out.println(wr.get());
结果:
aa
null
在GC之前存在引用,之后就被垃圾回收器回收了。
软引用和弱引用都非常适合保存那些可有可无的缓存数据,如果这么做,当系统内存不足时,这些缓存数据
会被回收,不会导致内存溢出,而当内存资源充足时,这些缓存数据又可以存在相当长的时间,从而起到加速
系统的作用。
虚引用
虚引用是所有引用最弱的一个,一个持有虚引用的对象,和没有引用几乎是一样的,随时都可能被垃圾回收器回收。当试图通过虚引用的get()方法取得强引用时,总会失败。并且虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程。
当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,销毁这个对象,将这个虚引用加入引用队列。
PhantomReference<String> pt=new PhantomReference<String>(str, null);
System.out.println(pt.get());
System.gc();
System.out.println(pt.get());
结果:
null
null
在这个输出结果可以看出,对虚引用的get操作,总是返回null,即便强引用还存在时也不例外,因为虚引用
的get()实现如下:
WeakHashMap类及实现
WeakHashMap类在java.util包内,它实现了Map接口,是HashMap的一种实现,它使用弱引用作为内部存储方案,WeakHashMap是弱引用的一种典型应用,它可以作为一种简单的缓存表解决方案。
WeakHashMap会在系统内存紧张时,使用弱引用,自动释放掉持有弱引用的内存数据.
如果希望在系统中通过WeakHashMap自动清理数据,就尽量不要在WeakHashMap使用强引用的key,因为这些强引用的key不会被回收,这样WeakHashMap的功能就会退化成HashMap,那么所有的表项就无法被清理。