Java中的四种引用
- FinalReference 强引用
- SoftReference 软引用
- WeakReference 弱引用
- PhantomReference 虚引用
为什么提供这四种引用
- 1、方便jvm进行垃圾回收
- 2、方便开发人员使用,开发人员可以灵活的决定某些对象的生命周期
四种引用的使用
FinalReference 强引用
类似于Object o = new Object()这类的引用,创建一个对象后,该引用会被保存在jvm中,而且只要强引用存在,垃圾回收器就不会回收调被引用的对象
日常使用
强引用的例子比比皆是,我们日常开发中我们经常会去new一个对象,而该new出来的对象便是强引用,也就是说只要该引用存在,垃圾回收器就不会被回收掉
JVM怎么知道引用是否存不存在(见另一篇文章介绍) JVM判断对象是否存活
SoftReference软引用
软引用关联的对象,在内存不够的情况下,会把这些软引用关联的对象列入垃圾回收范围中,然后进行垃圾回收,也就是说软引用并非完全安全的,在内存不够的情况下是会被垃圾回收器回收掉的. demo代码:
public class SoftReferenceDemo {
public static void main(String[] args) {
int count = 5;
SoftReference[] softReferences = new SoftReference[count];
for (int i = 0; i < count; i++) {
softReferences[i] = new SoftReference<TestObject>(new TestObject("TestObject-" + i));
}
//3、打印出softReference中所有的对象
for (int i = 0; i < count; i++) {
Object o = softReferences[i].get();
if (o == null) {
System.out.println("null");
} else {
System.out.println(((TestObject)o).name);
}
}
}
}
复制代码
这里实例了多个大对象,然后放入softReferences数组中,之后便遍历打印出其中的对象的命名,打印结果如下:
null
null
null
null
TestObject-4
复制代码
通过结果可以看出,前面四个对象因为内存不够而被垃圾回收器回收了
日常使用:
软引用是用来表示某个引用会被GC(垃圾处理器)收集的类。 当有引用指向某个obj的时候,通常发生GC的时候不会把这个对象处理掉,但是被软引用包装的对象,当应用内存将要被耗尽的时候-->即将发生OOM,垃圾处理器就会把它带走。这么看来,软应用的生命周期还是很长的,可以用来做缓存处理。
可以用以下方式创建一个引用:
SoftReference<String> ref = new SoftReference<String>("Hello world");
接收数据:
String value = ref.get();
if (value == null) {
// 如果被GC回收了 在这里重新初始化
}
// 逻辑处理
...
复制代码
软引用用作缓存:
public class SoftReferenceCache<K,V> {
private final HashMap<K, SoftReference<V>> mCache;
public SoftReferenceCache() {
mCache = new HashMap<K, SoftReference<V>>();
}
/**
* 将对象放进缓存中,这个对象可以在GC发生时被回收
*
* @param key key的值.
* @param value value的值型.
*/
public void put(K key, V value) {
mCache.put(key, new SoftReference<V>(value));
}
/**
* 从缓存中获取value
*
* @param key
*
* @return 如果找到的话返回value,如果被回收或者压根儿没有就返* 回null
*/
public V get(K key) {
V value = null;
SoftReference<V> reference = mCache.get(key);
if (reference != null) {
value = reference.get();
}
return value;
}
/**
* 从缓存中根据k删除对象
* @param key
*/
public void delete(K key){
mCache.remove(key);
}
}
复制代码
WeakReference使用
弱引用比软引用更弱,被弱引用关联的对象只能存活到发生下一次垃圾回收之前,也就是说当发生GC时,无论当前内存是否足够,都会被回收掉
demo代码:
public class WeakReferenceDemo {
public static void main(String[] args) {
WeakReference<String> sr = new WeakReference<>(new String("i am here"));
System.out.println(sr.get());
//手动gc
System.gc();
System.out.println(sr.get());
}
}
复制代码
先构建一个弱引用对象,然后在GC前先打印出来证明它存在过,之后手动调用gc,再次打印,可以看到对象已经没了.运行结果如下:
i am here
null
复制代码
PhantomReference虚引用
虚引用和上面不同的地方在于,一个对象是否有虚引用的存在,完全不会对其生存时间构成如何影响,并且也无法通过虚引用来获取一个对象的实例,也就是说跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收.
虚引用的作用就是能在这个对象被收集器回收时收到一个系统通知,实现追踪垃圾收集器的回收动作,比如在对象被回收的时候,会调用该对象的finalize方法.
- ReferenceQueue 引用队列
ReferenceQueue引用其实也可以归纳为引用中的一员,可以和上述三种引用类型组合使用[软引用、弱引用、虚引用]
在创建Reference时,手动将Queue注册到Reference中,而当该Reference所引用的对象被垃圾收集器回收时,JVM将会将该Reference放到队列中,而我们便可以对该队列做些其他业务,相当于一种通知机制
demo代码:
public class PhantomReferenceDemo {
public static void main(String[] args) {
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(new String("i am here"), referenceQueue);
//一直返回null,PhantomReference的get()结果必定为null
System.out.println("phantomReference.get()=" + phantomReference.get());
System.gc();
Reference<?> reference;
while ((reference = referenceQueue.poll()) != null) {
if (reference == phantomReference) {
System.out.println("被回收来");
}
}
}
}
复制代码
运行结果:
phantomReference.get()=null
被回收了
复制代码
从结果中可以看到从引用中get出来的对象为null,说明无法通过虚引用来获取一个对象的实例,并且在回收后会被放入队列中
Reference相关的概念
为了方便JVM进行管理,Reference是有状态的,可以分为以下四种状态:
- active一般来说内存一开始被分配的状态,而当引用的对象的可达性发生变化后gc就会将引用放入pending队列并将其状态改为pending状态
- pending指的是准备要被放进pending队列的对象
- enqueue指的是对象的内存已经被回收来
- inactive这是最终的状态,不能再变为其他状态
转载于:https://juejin.im/post/5d08b9f9e51d4577770e738c