在 jdk 1.2 及其以后,引入了强引用、软引用、弱引用、虚引用这四个概念。网上很多关于这四个概念的解释,但大多是概念性的泛泛而谈,今天我结合着代码分析了一下,首先我们先来看定义与大概解释(引用类型在包 java.lang.ref 里)。强引用(StrongReference),软引用(SoftReference),弱引用(WeakReference),虚引用(PhantomReference).
为了掩饰下面例子,将JVM堆内存设置为64M.
强引用(StrongReference)
强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型。举个例子来说:
Object obj = new Object();
这里的obj引用便是一个强引用,不会被GC回收。
/**
* @Description: 强引用
*
* 设置堆最大内存128M,超出将OutOfMemoryError
* @Date: 2018/11/12 0:01
*/
public class StrongReference {
public static void main(String[] args) {
int i =0;
List<Ref> list = new ArrayList<>();
for (;;){
int i1 = i++;
Ref ref = new Ref(i1);
list.add(ref);
System.out.println(i1 + "加到list中");
}
}
private static class Ref{
private byte[] bytes = new byte[1024*1024];//1M
private final int index;
private Ref(int index) {
this.index = index;
}
@Override
protected void finalize() throws Throwable {
System.out.println("--index---" + index + "---将要GC");
}
}
}
当堆内存满时,将OutOfMemoryError.
软引用(SoftReference)
软引用在JVM报告内存不足的时候才会被GC回收,否则不会回收,正是由于这种特性软引用在caching和pooling中用处广泛。软引用的用法:
Object obj = new Object();
SoftReference<Object> softRef = new SoftReference(obj);
// 使用 softRef.get() 获取软引用所引用的对象
Object objg = softRef.get();
/**
*SoftReference(软引用):
* 当发生GC(MinorGC/FullGC)时,当检测到JVM内存快要满了,将GC Soft Reference
* <P>
* SoftReference可能会OutOfMemoryError
* 1.当我们把睡眠时间调制1ms时,会报OutOfMemoryError
* 2.当我们把睡眠时间调制1s时,程序会一直执行下去,可以看到对象被GC
* 分析:时间调至1ms,这时还未来得及GC,又放入,会出现堆内存溢出
* 当1s时,有足够的时间去GC.不会全部GC掉
* 总结:在缓存中,一般放的次数远远小于放的次数,不可能不断地放入缓存,因此用SoftReference,绝大多时候
* 不会报OutOfMemoryError
*
* <P/>
*/
public class Soft_Reference {
public static void main(String[] args) throws InterruptedException {
int i =0;
List<SoftReference<Ref>> list = new ArrayList<>();
for (;;){
int i1 = i++;
list.add(new SoftReference<>(new Ref(i1)));
System.out.println(i1 + "加到list中");
TimeUnit.MILLISECONDS.sleep(1000);
}
}
private static class Ref{
private byte[] bytes = new byte[1024*1024];//1M
private final int index;
private Ref(int index) {
this.index = index;
}
@Override
protected void finalize() throws Throwable {
System.out.println("--index---" + index + "---将要GC");
}
}
}
弱引用(WeakReference)
当GC一但发现了弱引用对象,将会释放WeakReference所引用的对象
/**
*WeakReference(弱引用):
* 当发生GC(MinorGC/FullGC)时,都会被回收掉。
*/
public class Weak_Reference {
public static void main(String[] args) throws InterruptedException {
int i =0;
List<WeakReference<Ref>> list = new ArrayList<>();
for (;;){
int i1 = i++;
list.add(new WeakReference<>(new Ref(i1)));
System.out.println(i1 + "加到list中");
TimeUnit.MILLISECONDS.sleep(100);
}
}
private static class Ref{
private byte[] bytes = new byte[1024*1024];//1M
private final int index;
private Ref(int index) {
this.index = index;
}
@Override
protected void finalize() throws Throwable {
System.out.println("--index---" + index + "---将要GC");
}
}
}
虚引用(PhantomReference).
当GC一但发现了虚引用对象,将会将PhantomReference对象插入ReferenceQueue队列,而此时PhantomReference所指向的对象并没有被GC回收,而是要等到ReferenceQueue被你真正的处理后才会被回收。虚引用的用法:
Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue);
// 调用phanRef.get()不管在什么情况下会一直返回null
Object objg = phanRef.get();
// 如果obj被置为null,当GC发现了虚引用,GC会将phanRef插入进我们之前创建时传入的refQueue队列
// 注意,此时phanRef所引用的obj对象,并没有被GC回收,在我们显式地调用refQueue.poll返回phanRef之后
// 当GC第二次发现虚引用,而此时JVM将phanRef插入到refQueue会插入失败,此时GC才会对obj进行回收
Reference<? extends Object> phanRefP = refQueue.poll();
虚引用在实现一个对象被回收之前必须做清理操作是很有用的。有时候,他们比finalize()方法更灵活。
很明显的,虚引用可以用来做对象被回收之前的清理工作。
//TODO
对于Reference先介绍到这,能力有限,后面再继续补充.
参考:https://blog.csdn.net/aitangyong/article/details/39453365