Java引用详解

原文链接:https://blog.csdn.net/sunxianghuang/article/details/52267282

https://www.cnblogs.com/yw-ah/p/5830458.html

强引用(Strong Reference)

强引用是指在程序代码中普遍存在的,类似“Object obj=new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。

public class StrongReferenceTest {
private static class BiggerObject{//占用空间的一个大对象
public int[] values;
public String name;
public BiggerObject(String name){
this.name=name;
values=new int[1024];
}
}
public static void main(String[] args) {
int count=10000;//对象的个数,保证使得堆内存溢出
BiggerObject[] values=new BiggerObject[count];
for(int i=0;i<count;i++){
values[i]=new BiggerObject("Object-"+i);
}
for(int i=0;i<10;i++){
System.out.println(values[i].name);
} 
} 
}

输出:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid668.hprof ...
Heap dump file created [13980085 bytes in 0.181 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at StrongReferenceTest$BiggerObject.<init>(StrongReferenceTest.java:8)
    at StrongReferenceTest.main(StrongReferenceTest.java:15)

因为垃圾收集器无法回收强引用关联着的对象,从而导致堆内存溢出。

软引用(Soft Reference)

用来描述一些还有用并非必要的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列入回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。JDK 1.2之后,提供了SoftReference类来实现软引用。

import java.lang.ref.SoftReference;

public class SoftReferenceTest {
private static class BiggerObject{//占用空间的一个大对象
public int[] values;
public String name;
public BiggerObject(String name){
this.name=name;
values=new int[1024];
}
}
public static void main(String[] args) {
int count=100000;//对象数量为100000,保证使得堆内存溢出
SoftReference[] values=new SoftReference[count];
for(int i=0;i<count;i++){
values[i]=new SoftReference<BiggerObject>(new BiggerObject("Object-"+i));
}
System.out.println(((BiggerObject)(values[values.length-1].get())).name);
for(int i=0;i<10;i++){
System.out.println(((BiggerObject)(values[i].get())).name);
} 
} 
}

输出:

Object-99999
Exception in thread "main" java.lang.NullPointerException
    at SoftReferenceTest.main(SoftReferenceTest.java:21)

第一行输出说明,使用软引用后,原本由于堆内存溢出而无法正常执行的代码段“正常的”执行成功;

但是,当我们访问早期创建的那些对象时,却报java.lang.NullPointerException异常,说明早期创建的对象已经被垃圾收集器回收了。

import java.lang.ref.SoftReference;

public class SoftReferenceTest {
private static class BiggerObject{//占用空间的一个大对象
public int[] values;
public String name;
public BiggerObject(String name){
this.name=name;
values=new int[1024];
}
}
public static void main(String[] args) {
int count=100;//对象数量改为100,保证堆内存不会溢出
SoftReference[] values=new SoftReference[count];
for(int i=0;i<count;i++){
values[i]=new SoftReference<BiggerObject>(new BiggerObject("Object-"+i));
}
System.gc();//强制进行垃圾回收
System.out.println(((BiggerObject)(values[values.length-1].get())).name);
for(int i=0;i<10;i++){
System.out.println(((BiggerObject)(values[i].get())).name);
} 
} 
}

输出:

Object-99

Object-0

Object-1

Object-2

Object-3

Object-4

Object-5

Object-6

Object-7

Object-8

Object-9

当堆内存足够时,即使我们强制进行垃圾回收,软引用关联着的对象也不会被回收。

弱引用(WeakReference)

弱引用也是用来描述非必要对象的,但是他的强度比软引用更弱一些,被软引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。JDK 1.2之后,提供了WeakReference类来实现弱引用。

public class WeakReferenceTest {
private static class BiggerObject{//占用空间的一个大对象
public int[] values;
public String name;
public BiggerObject(String name){
this.name=name;
values=new int[1024];
}
}
public static void main(String[] args) {
int count=10000;//对象数量为10000,保证使得堆内存溢出
WeakReference[] values=new WeakReference[count];
for(int i=0;i<count;i++){
values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i));
} 
System.out.println(((BiggerObject)(values[values.length-1].get())).name);
for(int i=0;i<10;i++){
System.out.println(((BiggerObject)(values[i].get())).name);
} 
} 
}

输出:

Object-9999
Exception in thread "main" java.lang.NullPointerException
    at WeakReferenceTest.main(WeakReferenceTest.java:22)

输出结果,与软引用相同。

public class WeakReferenceTest {
private static class BiggerObject{//占用空间的一个大对象
public int[] values;
public String name;
public BiggerObject(String name){
this.name=name;
values=new int[1024];
}
}
public static void main(String[] args) {
int count=100;//对象数量改为100,保证堆内存不会溢出
WeakReference[] values=new WeakReference[count];
for(int i=0;i<count;i++){
values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i));
} 
System.out.println(((BiggerObject)(values[values.length-1].get())).name);
for(int i=0;i<10;i++){
System.out.println(((BiggerObject)(values[i].get())).name);
} 
} 
}

输出:

Object-99
Object-0
Object-1
Object-2
Object-3
Object-4
Object-5
Object-6
Object-7
Object-8
Object-9

当堆内存够用时,正常输出。

public class WeakReferenceTest {
private static class BiggerObject{//占用空间的一个大对象
public int[] values;
public String name;
public BiggerObject(String name){
this.name=name;
values=new int[1024];
}
}
public static void main(String[] args) {
int count=100;//对象数量改为100,保证堆内存不会溢出
WeakReference[] values=new WeakReference[count];
for(int i=0;i<count;i++){
values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i));
} 
System.out.println(((BiggerObject)(values[values.length-1].get())).name);
System.gc();//强制进行垃圾回收
for(int i=0;i<10;i++){
System.out.println(((BiggerObject)(values[i].get())).name);
} 
} 
}

即使堆内存够用,当我们强制进行垃圾回收时,弱引用所引用的对象还是被垃圾收集器回收。

虚引用

一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。

垃圾回收时回收,无法通过引用取到对象值,可以通过如下代码实现

Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
obj=null;
pf.get();//永远返回null
pf.isEnQueued();//返回是否从内存中已经删除

虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
虚引用主要用于检测对象是否已经从内存中删除。

原文地址:https://www.cnblogs.com/fswhq/p/9888697.html