众所周知,Java虚拟机中存在强引用、软引用、弱引用和虚引用4中类型,这4中类型在虚拟机gc的时候会区别对待。首先我们来思考几个问题:我们为什么要学这个?学这个有什么用?,能解决什么问题?学任何东西想清楚这几个问题,学习方向就知道了。
毕业以后的一切学习,无非就两个目的,1挣钱,2解决问题。
1学习以后技术 提高,解决问题能力提高,加薪
2熟悉引用的情况,可以写出对jvm更友好的代码,让jvm垃圾回收效率更好。
强引用
其实我们new操作都是强引用,是一个普遍操作,当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
String str = "abc";
List list = new Arraylist();
list.add(str);
这个例子中,jvm内存不足时, 在list集合里的数据不会释放
我们来看clear 方法
public void clear() {
modCount++; // clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null; size = 0;}
在ArrayList类中定义了一个私有的变量elementData数组,在调用方法清空数组时可以看到为每个数组内容赋值为null。不同于elementData=null,强引用仍然存在,避免在后续调用 add()等方法添加元素时进行重新的内存分配。使用如clear()方法中释放内存的方法对数组中存放的引用类型全部置空,这样就可以及时释放内存。
软引用
软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
从代码层面理解一下
publicstaticvoidmain(String[] args) {
System.out.println("start");
Objobj=newObj();
SoftReferencesr=newSoftReference(obj);
obj=null;
System.out.println(sr.get());
System.out.println("end");
ReferenceQueue可以配合SoftReference一起使用,在gc的时候可以一起回收。
运行结果
start
test$Obj@330bedb4
end
弱引用
弱引用的使用和软引用类似,只是关键字变成了WeakReference:
WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1024\*1024\*10]);
System.out.println(weakReference.get());
弱引用的特点是不管内存是否足够,只要发生GC,都会被回收:
WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1]);
System.out.println(weakReference.get());
System.gc();
System.out.println(weakReference.get());
运行结果:
[B@11d7fffnull
我们可以看到明明内存还很充足,但是触发了GC,资源还是被回收了。
弱引用在很多地方都有用到,比如ThreadLocal、WeakHashMap。
虚引用
正如它的名字,虚引用就是如同虚设,任何时候虚拟机都可以回收他,也不影响对象的生命周期。
使用虚引用需要注意,虚引用必须和引用队列关联使用。
当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
虚引用的使用会在nio时管理堆在内存。加速内存的回收。