Java中存在四种引用:
StrongReference
(强引用)SoftReferenc
(软引用)WeakReferenc
(弱引用)PhantomReference
(虚引用)
强引用
java中的引用默认就是强引用,任何一个对象的赋值操作就产生了对这个对象的强引用。
如:Object obj = new Object();
特性:只要有强引用存在,被引用的对象就不会被垃圾回收。当内存不足时,抛出 OutOfMemoryError
异常。
软引用
SoftReference
软引用是用来描述一些还有用,但非必须的对象。
只有在内存不足的情况下,被引用的对象才会被回收。
弱引用
WeakReference
也是用来描述那些非必须对象的,但是它的强度比软引用更弱一些。
weekReference
引用的对象只要垃圾回收执行,就会被回收,而不管是否内存不足。
示例:
我们在操作threadlocal
的时候,是定义了一个静态变量:
static ThreadLocal<String> threadlocal = new ThreadLocal<>()
;
此时threadlocal引用是强引用。
然后我们通过set操作,以 threadlocal
为键,存入threadlocalmap里的数组table[i]
,这时 table[i]
内的key指向theadlocal的引用就是弱引用,当gc(垃圾回收)的时候,这个引用就会被回收,然后key就变成了null。
虚引用
- 判断对象是否被回收,通过检查引用队列中是否包含虚引用来判断是否被回收。
- 当对象被回收的时候,在引用队列判断的时候,可以根据需要做一些事情,比如资源清理等等。
Phantom Reference
,/ˈfæntəm/
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。
虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中
。
它不能单独使用也不能通过它访问对象
,虚引用必须和引用队列(ReferenceQueue)联合使用。
虚引用的主要作用是跟踪对象被垃圾回收的状态,仅仅是提供了一种确保对象被finalize以后,做某些事情的机制。PhantomRefernce的get方法总是返回null,因此无法访问对应的引用对象,其意义在于说明一个对象已经进入finalization阶段,可以被gc回收,用来实现比finalization机制更灵活的回收操作。
换句话说,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步处理(允许我们在对象被销毁后,做一些我们自己想做的事情)。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
虚引用的主要作用是跟踪对象被垃圾回收器回收的活动。 它与软引用和弱引用的一个关键区别在于,虚引用必须与引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现该对象还有虚引用,就会把对应的虚引用加入到与之关联的引用队列中。这样,通过检查引用队列中是否加入了虚引用,可以了解被引用对象是否将要被垃圾回收器回收,并据此执行一些必要的操作,如资源回收。
此外,虚引用的这种特性使得它特别适用于需要监控对象生命周期并进行相应资源管理的场景,例如在对象被回收前执行清理操作或其他逻辑。
它的作用在于跟踪垃圾回收过程,在对象被收集器回收时收到一个系统通知。 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,将这个虚引用加入引用队列,在其关联的虚引用出队前,不会彻底销毁该对象。 所以可以通过检查引用队列中是否有相应的虚引用来判断对象是否已经被回收了。
如果一个对象没有强引用和软引用,对于垃圾回收器而言便是可以被清除的,在清除之前,会调用其finalize方法,如果一个对象已经被调用过finalize方法但是还没有被释放,它就变成了一个虚可达对象。
与软引用和弱引用不同,显式使用虚引用可以阻止对象被清除,只有在程序中显式或者隐式移除这个虚引用时,这个已经执行过finalize方法的对象才会被清除。想要显式的移除虚引用的话,只需要将其从引用队列中取出然后扔掉(置为null)即可。
因为设置的虚拟机堆大小比较小,所以创建一个100k的对象时直接进入了老年代,等到发生Full GC时才会被扫描然后回收。
适用场景
使用虚引用的目的就是为了得知对象被GC的时机,所以可以利用虚引用来进行销毁前的一些操作,比如说资源释放等。
事实上,虚引用有一个很重要的用途就是用来做堆外内存的释放,DirectByteBuffer就是通过虚引用来实现堆外内存的释放的。