引用类型可以说是整个Java开发的灵魂所在,如果没有合理的引用操作,那么就有可能产生垃圾问题,但是对于引用也需要有一些合理化的设计。在很多的时候并不是所有的对象都需要被我们一直使用,那么就需要对引用的问题做进一步的思考。从JDK1.2之后关于引用提出了四种方案:
●强引用:当内存不足的时候,JVM宁可出现OutOfMemory错误停止,也需要进行保存,并且不会将此空间回收;
●软引用:当内存不足的时候,进行对象的回收处理,往往用于高速缓存中;
●弱引用:不管内存是否紧张,只要由垃圾产生了,那么立即回收;
●幽灵引用:和没有引用是一样的。
强引用是JVM默认的支持模式,即:在引用的期间内,如果该堆内存被指定的栈内存有联系,那么该对象就无法被GC所回收,而一旦出现了内存空间不足,就会出现“OutOfMemoryError”错误信息。
范例:观察强引用。
package cn.test.demo;
public class TestDemo{
public static void main(String[]args){
Object obj=new Object();//强引用,默认的支持
Object ref=obj;//引用传递
obj=null;//断开了一个连接
System.gc();
System.out.println(ref);
}
}
如果此时堆内存有一个栈内存指向,那么该对象将无法被GC回收。
强引用是我们一直在使用的模式,并且也是以后开发之中主要的使用模式,正因为强引用具备这样的内存分配异常问题,所以,尽量少实例化对象。
在许多的开源组件之中,往往会使用软引用作为缓存组件出现,其最大的特点在于:不足时回收,充足时不回收。想实现软引用,则需要有一个单独的类来实现控制:java.lang.ref.SoftReference
。这个类的方法如下:
●构造:public SoftReference(T referent)
●取出数据:public T get()
范例:观察软引用
package cn.test.demo;
import java.lang.ref.SoftReference;
public class TestDemo{
public static void main(String[]args){
Object obj=new Object();
SoftReference
如果此时内存空间充足,那么对象将不会回收,如果空间不充足,则会进行回收。
package cn.test.demo;
import java.lang.ref.SoftReference;
public class TestDemo{
public static void main(String[]args){
Object obj=new Object();
String str="hello";
obj=null;//断开连接
SoftReference ref=new SoftReference;//软引用
try{
for(int x=0;xcatch(Throwable e){
}
System.out.println(ref.get()+"##############################");
}
}
弱引用本质的含义指的是说只要一进行GC处理,那么所引用的对象将会被立刻回收。弱引用需要使用的是Map接口的子类:java.util.WeakHashMap
。
范例:观察弱引用
package cn.test.demo;
import java.lang.ref.SoftReference;
public class TestDemo{
public static void main(String[]args){
String key=new String(“hi”);
String value=new String(“hello”);
Map map=new WeakHashMap();
map.put(key,value);
System.out.println(map.get(key));
key=null;
System.out.println(map);
System.gc();
System.out.println(map);
}
}
一旦出现GC,则必须进行回收处理,而且一回收一个准。
HashMap与WeakHashMap区别?
HashMap是强引用,而WeakHashMap是弱引用。
在java.lang.ref包中存在有一个WeakReference的一个子类。
范例:观察WeakReference
package cn.test.demo;
import java.lang.ref.SoftReference;
public class TestDemo{
public static void main(String[]args){
String key=new String(“hi”);
WeakReference map=new WeakHashMap(key);
Key=null;
System.out.println(ref.get());
System.gc();
System.out.println(ref.get());
}
}
弱引用之所以不敢轻易使用的原因,就是因为其本身一旦有了GC之后就会立刻清空,这个对于程序的开发不利。
所谓的引用队列就是保存那些准备被回收的对象。很多的时候所有的对象的回收扫描都是从根对象开始的。
那么对于整个GC而言,如果要想确定那些对象可以被回收,就必须确定好引用的强度,这个也就是所谓的引用路径的设置。
如果现在要找到对象5,那么很明显1找到5属于“强”+“软”,而2找到5属于“强”+“弱”。软引用要比弱引用保存的强,所以这个时候实际上对于对象的引用而言,如果要进行引用的关联判断,那么就必须找到强关联,那么为了避免非强引用对象所带来的内存引用问题,所以提供有一个引用队列的概念,如果在创建软引用或者弱引用类型的时候使用了引用队列的方式,则这个对象被回收之后会自动保存在引用队列之中。
范例:使用引用队列
package cn.test.demo;
import java.lang.ref.SoftReference;
public class TestDemo{
public static void main(String[]args)throws Exception{
Object obj=new Object();
ReferenceQueue queue=new ReferenceQueue<>();
WeakReference ref=new WeakReference(obj,queue);
System.out.println(queue.poll());
obj=null;
System.gc();
Tread.sleep(200); //延迟200毫秒
System.out.println(queue.poll());
}
}
这种引用队列主要是做一些被回收对象的控制,意义不大,了解即可。
永远取得不了的数据就叫做幽灵引用。
范例:观察幽灵引用
package cn.test.demo;
import java.lang.ref.SoftReference;
public class TestDemo{
public static void main(String[]args) throws Exception{
Object obj=new Object();
ReferenceQueue queue=new ReferenceQueue();
PhantomReference ref=new PhantomReference(obj,queue);
System.gc();
System.out.println(ref.get());
System.out.println(queue.poll());
}
}
所有保存在幽灵引用类型中的数据都不会真正的保留。