Date: 2017-01-14 10:10:10
java基础-强、软、弱、虚引用
jdk1.2之后java对引用的概念进行了扩充,分为强引用,软引用,弱引用,虚引用。
- 强引用(FinalReference):类似Object obj=new Object();这类的引用只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
- 软引用(SoftReference):用来描述一些还有用但非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列为第二次回收范围之中。
- 弱引用(WeakReference):描述非必须的对象,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当GC工作时,无论当前内存是否足够,都会回收掉只被弱引用的对象。weakReference类来实现弱引用
- 虚引用(PhantomReference):一个对象是否有虚引用完全不会对其生存构成影响,也无法通过虚引用来取得一个对象的实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知,PhantomReference引用必须ReferenceQueue队列一起使用。
FinalReference引用,FinalReference不对外提供使用,该引用是在我们调用对象的finalize方法的时候,系统才会引入FinalReference引用。
强弱关系:强>软>弱>虚
所有的引用都继承自Reference类,所以我们先来分析一下Reference是个什么东西?
Reference & ReferenceQueue分析
Reference介绍
Reference引用对象的抽象基类,这个类中定义了所有引用对象的常用操作。
定义:Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互。即可以使用Reference对象来引用其它对象,但是最后还是会被垃圾收集器回收。程序有时候也需要在对象回收后被通知,以告知对象的可达性发生变更。
看了Reference的定义之后才明白,哦,原来JDK定义了那么多引用,是为了让java开发人员和GC交互的。
开发人员在一些场景下,比如缓存,key的对象引用不是那么重要,但又不知道什么时候清除缓存,这个时候我们可以让GC来帮我们解决问题,使用WeakReference,GC在下一次比较时就会把他给直接回收了。这里这是一个简单的例子。
ReferenceQueue介绍
ReferenceQueue,在适当的时候检测到对象的可达性发生改变后,垃圾回收器就将已注册的引用对象添加到此队列中。
下面的源码分析也会提到,ReferenceQueue这个队列里面的数据,不是我们主动往里面塞数据的,而是GC在回收对象的时候往里面塞的。
Reference源码分析
Reference类的4中状态:
- Active:Active状态的Reference会受到GC的特别关注,当GC察觉到引用的可达性变化为其它的状态之后,它的状态将变化为Pending或Inactive,到底转化为Pending状态还是Inactive状态取决于此Reference对象创建时是否注册了queue.如果注册了queue,则将添加此实例到pending-Reference list中。 新创建的Reference实例的状态是Active。
- Pending:在pending-Reference list中等待着被Reference-handler 线程入队列queue中的元素就处于这个状态。没有注册queue的实例是永远不可能到达这一状态。
- Enqueued:当实例被移动到ReferenceQueue中时,Reference的状态为Inactive。没有注册ReferenceQueue的不可能到达这一状态的。
- Inactive:一旦一个实例变为Inactive,则这个状态永远都不会再被改变。
成员变量
//用于保存对象的引用,GC会根据不同Reference来特别对待
private T referent; /* 通过GC特殊处理 */
//如果需要通知机制,则保存的对对应的队列
ReferenceQueue<? super T> queue;
//* 这个用于实现一个单向循环链表,用以将保存需要由ReferenceHandler处理的引用 */
Reference next;
transient private Reference<T> discovered; /* used by VM */
static private class Lock { };
private static Lock lock = new Lock();
/*
* 引用等待队列列表。收集器添加对该列表的引用,而引用处理程序线程将它们删除。此列表受上述锁对象的保护。
* 这个参数的值是有jvm来赋值的哦,所以在代码中没看到赋值的操作。
*/
private static Reference pending = null;
初始化
//不带队列的,则不会进入到前面提到过的Pending这种状态中。也就是不会有消息通知
Reference(T referent) {
this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
Reference内部类
//辅助类
private static class ReferenceHandler extends Thread {
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
for (;;) {
Reference r;
synchronized (lock) {
//这个pending值是有jvm,GC的时候赋值的。
if (pending != null) {
r = pending;
Reference rn = r.next;//构成一个单链表
pending = (rn == r) ? null : rn;
r.next = r;//循环的单链表
} else {
try {
// 没有则等待,后续加入元素会调用lock.notify唤醒
//这里只是看到网上这么说的,但是我没看到那里有notify唤醒wait。有待验证
lock.wait();
} catch (InterruptedException x) { }
continue;
}
}
// Fast path for cleaners
if (r instanceof Cleaner) {
((Cleaner)r).clean();
continue;
}
// 如果该Reference注册了对应的Queue,则加入到该Queue中
ReferenceQueue q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
}
}
}
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
/* If there were a special system-only priority greater than
* MAX_PRIORITY, it would be used here
*/
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
}
ReferenceQueue消息通知
ReferenceQueue,这个队列的存在其实就是为了一个消息通知。就是说GC把对象回收了,然后在ReferenceQueue队列里面签个到。程序里面可以通过ReferenceQueue这个队列的值,哦,我的对象被回收了。
也许你会问,对象回收了,然后又把对象存ReferenceQueue里面,那不就和没回收一样吗,内存还是被占用着。我当时也是这么想的?
我们来做一个测试
设置vm大小:-verbose:gc -Xmx20M -Xms20M -Xmn10M -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintGCDetails -XX:SurvivorRatio=8
-Xmx20M:设置JVM最大可用内存为20M
-Xms20M:设置JVM促使内存为20m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xmn10M:设置年轻代大小为10
-XX:+PrintGCDetails:打印gc详细日志
public class WeakReferenceDome {
private static List<Reference> roots = new ArrayList<Reference>();
public static void main(String[] args) {
final ReferenceQueue rq = new ReferenceQueue();
//2.这里单独起一个线程作为队列监控器,用来监控对象被回收。
new Thread(new Runnable() {
public void run() {
Reference r;
while (true) {
r = rq.poll();
if (r == null) {
continue;
}
System.out.println("r:" + r);
//为null说明referent被回收
System.out.println("get:" + r.get());
}
}
}).start();
for (int i = 0; i < 20; i++) {
//注意a是一个强引用哦,但是a在for的的下一次循环之后就超出了它的作用域,就自我销毁了。所以不会影响到r的弱引用回收。
//下文中的weakReference会有介绍强,弱同时引用一个对象哦!
byte[] a = new byte[1024 * 1024];
//1.一旦发生GC,a被回收了,那么GC将会发消息通知我们,发送的通知消息就存到了rq队列里面,可以通过上面的队列监控器得知。
Reference r = new WeakReference(a, rq);
System.out.println(i + "r=" + r);
roots.add(r);
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结果:
0r=java.lang.ref.WeakReference@5df9cdda
1r=java.lang.ref.WeakReference@3fb2bb77
2r=java.lang.ref.WeakReference@6f31a24c
3r=java.lang.ref.WeakReference@2396649c
4r=java.lang.ref.WeakReference@66a75004
5r=java.lang.ref.WeakReference@72766b42
[GC [PSYoungGen: 7471K->448K(9216K)] 7471K->448K(19456K), 0.0043990 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
6r=java.lang.ref.WeakReference@591c5342
r:java.lang.ref.WeakReference@72766b42
get:null
r:java.lang.ref.WeakReference@66a75004
get:null
r:java.lang.ref.WeakReference@2396649c
get:null
r:java.lang.ref.WeakReference@6f31a24c
get:null
r:java.lang.ref.WeakReference@3fb2bb77
get:null
r:java.lang.ref.WeakReference@5df9cdda
get:null
。。。。。其他就不粘贴了
Heap
PSYoungGen total 9216K, used 8011K [0x00000007ff600000, 0x0000000800000000, 0x0000000800000000)
eden space 8192K, 92% used [0x00000007ff600000,0x00000007ffd6ee20,0x00000007ffe00000)
from space 1024K, 39% used [0x00000007fff00000,0x00000007fff64010,0x0000000800000000)
to space 1024K, 0% used [0x00000007ffe00000,0x00000007ffe00000,0x00000007fff00000)
ParOldGen total 10240K, used 0K [0x0000000780000000, 0x0000000780a00000, 0x00000007ff600000)
object space 10240K, 0% used [0x0000000780000000,0x0000000780000000,0x0000000780a00000)
PSPermGen total 21504K, used 3051K [0x000000077ae00000, 0x000000077c300000, 0x0000000780000000)
object space 21504K, 14% used [0x000000077ae00000,0x000000077b0fafe8,0x000000077c300000)
解说:
回收前:
0r=java.lang.ref.WeakReference@5df9cdda
get:1M;//这里是我自己加的,因为get到的是一个byte 1M个字节的二进制数据,显示出来不好看。可以自己尝试输出看一下。
回收后:
r:java.lang.ref.WeakReference@5df9cdda
get:null
要知道:
byte[] a = new byte[1024 * 1024];
Reference r = new WeakReference(a, rq);
System.out.println(i + “r=” + r);
0r里面引用的对象是a,大小是1M啊。
回收后,只有一个0r的引用,a这个1M的对象已经被回收了,按正常逻辑来a这个对象被回收了,0r这个引用也就指向了null,引用也是不存在了;但是GC在对象回收了之后,把0r这个引用存到了队列里面;一个空引用而已,大小估计也就1个字节而已;那么存储这个引用干嘛呢?这个不是打自己的脸吗,因为你需要所以GC就给你了啊。
假如我们使用new WeakReference(a, null); GC把a给回收掉了,我们获取到的0r也是空的,而不是java.lang.ref.WeakReference@5df9cdda。
我们给了WeakReference这个一个队列,GC会在回收a之后把回收这件事通知一下ReferenceQueue,我们可以通过监控ReferenceQueue这个队列,了解我们的a对象是否被回收了,什么时候被回收的,仅此而已。
SoftReference
软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM(内存溢出)的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
使用软引用时,需要在启动jvm时加入-XX:SoftRefLRUPolicyMSPerMB=0参数。
free_heap 表示当前堆剩余的内存,单位是MB
interval 表示最近一次GC’s clock 和 当前我们要判断的softReference的timestamp 差值
ms_per_mb is a constant number of milliseconds to keep around a SoftReference for each free megabyte in the heap(可以通过-XX:SoftRefLRUPolicyMSPerMB来设定)
那么判断依据就是: interval <= freeheap * ms_per_mb,如果为true,则保留,false则进行对象清除。 SoftReferences will always be kept for at least one GC after their last access。_ 因为 只要调用一次,那么clock和timestamp的值就会一样,clock-timestamp则为0,一定小于等于free_heap * ms_per_mb。 OpenJDK的大概referencePolicy.cpp代码是:
void LRUMaxHeapPolicy::setup() {
size_t max_heap = MaxHeapSize;
max_heap -= Universe::get_heap_used_at_last_gc();
max_heap /= M;
_max_interval = max_heap * SoftRefLRUPolicyMSPerMB;
assert(_max_interval >= 0,”Sanity check”);
}
bool LRUMaxHeapPolicy::should_clear_reference(oop p,
jlong timestamp_clock) {
jlong interval = timestamp_clock – java_lang_ref_SoftReference::timestamp(p);
assert(interval >= 0, “Sanity check”);
// The interval will be zero if the ref was accessed since the last scavenge/gc.
if(interval <= _max_interval) {
return false;
}
return true;
}
可见,SoftReference在一定程度上会影响JVM GC的,例如softly-reachable对应的referent多次垃圾回收仍然不满足释放条件,那么它会停留在heap old区,占据很大部分空间,在JVM没有抛出OutOfMemoryError前,它有可能会导致频繁的Full GC。
原文地址:http://blog.youkuaiyun.com/androidstar_cn/article/details/54710652
设置vm大小:-verbose:gc -Xmx20M -Xms20M -Xmn10M -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintGCDetails -XX:SurvivorRatio=8
public class WeakReferenceDome {
private static List<Reference> roots = new ArrayList<Reference>();
public static void main(String[] args) {
final ReferenceQueue rq = new ReferenceQueue();
new Thread(new Runnable() {
public void run() {
Reference r;
while (true) {
r = rq.poll();
if (r == null) {
continue;
}
System.out.println("r:" + r);
//为null说明referent被回收
System.out.println("get:" + r.get());
}
}
}).start();
for (int i = 0; i < 20; i++) {
byte[] a = new byte[1024 * 1024];
// 分别验证SoftReference,WeakReference,PhantomReference
Reference r = new SoftReference(a, rq);
//Reference r = new WeakReference(a, rq);
//Reference r = new PhantomReference(a, rq);
System.out.println(i + "r=" + r);
roots.add(r);
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果:
0r=java.lang.ref.SoftReference@5df9cdda
1r=java.lang.ref.SoftReference@68e1ca74
2r=java.lang.ref.SoftReference@3fb2bb77
3r=java.lang.ref.SoftReference@6f31a24c
4r=java.lang.ref.SoftReference@2396649c
5r=java.lang.ref.SoftReference@66a75004
[GC [PSYoungGen: 7471K->416K(9216K)] 7471K->6560K(19456K), 0.0050410 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]
[Full GC [PSYoungGen: 416K->0K(9216K)] [ParOldGen: 6144K->310K(21504K)] 6560K->310K(30720K) [PSPermGen: 3043K->3042K(21504K)], 0.0166540 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
6r=java.lang.ref.SoftReference@529e3fc2
r:java.lang.ref.SoftReference@66a75004
get:null
r:java.lang.ref.SoftReference@2396649c
get:null
r:java.lang.ref.SoftReference@6f31a24c
get:null
r:java.lang.ref.SoftReference@3fb2bb77
get:null
r:java.lang.ref.SoftReference@68e1ca74
get:null
r:java.lang.ref.SoftReference@5df9cdda
get:null
7r=java.lang.ref.SoftReference@136c03ee
8r=java.lang.ref.SoftReference@18760838
9r=java.lang.ref.SoftReference@6d15a113
10r=java.lang.ref.SoftReference@27021e58
11r=java.lang.ref.SoftReference@7c163769
12r=java.lang.ref.SoftReference@16900e24
[GC [PSYoungGen: 7426K->128K(9216K)] 7737K->7606K(30720K), 0.0021350 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
13r=java.lang.ref.SoftReference@75e13ce3
14r=java.lang.ref.SoftReference@1664978b
15r=java.lang.ref.SoftReference@26193229
16r=java.lang.ref.SoftReference@402c3549
17r=java.lang.ref.SoftReference@165e6c89
18r=java.lang.ref.SoftReference@1127a1d8
19r=java.lang.ref.SoftReference@40f274b4
Heap
PSYoungGen total 9216K, used 7629K [0x00000007ff600000, 0x0000000800000000, 0x0000000800000000)
eden space 8192K, 91% used [0x00000007ff600000,0x00000007ffd53588,0x00000007ffe00000)
from space 1024K, 12% used [0x00000007fff00000,0x00000007fff20000,0x0000000800000000)
to space 1024K, 0% used [0x00000007ffe00000,0x00000007ffe00000,0x00000007fff00000)
ParOldGen total 21504K, used 7478K [0x0000000780000000, 0x0000000781500000, 0x00000007ff600000)
object space 21504K, 34% used [0x0000000780000000,0x000000078074da48,0x0000000781500000)
PSPermGen total 21504K, used 3051K [0x000000077ae00000, 0x000000077c300000, 0x0000000780000000)
object space 21504K, 14% used [0x000000077ae00000,0x000000077b0fac60,0x000000077c300000)
从结果中可以看出;软引用在被回收时发生了一次GC,一次FULL GC。
如果不加这个参数:-XX:SoftRefLRUPolicyMSPerMB=0,
是看不到:
r:java.lang.ref.SoftReference@66a75004
get:null
就是说被回收了,在回收队列里面看不到。
public static void main(String[] args) {
Object obj = new Object();
SoftReference<Object> sf = new SoftReference(obj);
System.out.println(sf.get() != null);
System.gc();
obj = null;
System.out.println(sf.get() != null);
}
结果都为true;
软引用在内存足够的情况下是不会被回收的,只有在内存不足的情况下才会被回收。
WeakReference
Java中的弱引用具体指的是java.lang.ref.WeakReference类,我们首先来看一下官方文档对它做的说明:
弱引用对象的存在不会阻止它所指向的对象变被垃圾回收器回收。弱引用最常见的用途是实现规范映射(canonicalizing mappings,比如哈希表)。
假设垃圾收集器在某个时间点决定一个对象是弱可达的(weakly reachable)(也就是说当前指向它的全都是弱引用),这时垃圾收集器会清除所有指向该对象的弱引用,然后垃圾收集器会把这个弱可达对象标记为可终结(finalizable)的,这样它们随后就会被回收。与此同时或稍后,垃圾收集器会把那些刚清除的弱引用放入创建弱引用对象时所登记到的引用队列(Reference Queue)中。
public static void main(String[] args) {
WeakReference<String> sr = new WeakReference<String>(new String("hello"));
System.out.println(sr.get());
System.gc(); //通知JVM的gc进行垃圾回收
System.out.println(sr.get());
String str = "hello2";//强引用
WeakReference<String> sr2 = new WeakReference<String>(str);
System.out.println(sr2.get());
System.gc();
System.out.println(sr2.get());
}
输出结果:
hello
[GC [PSYoungGen: 999K->352K(9216K)] 999K->352K(19456K), 0.0018400 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen: 352K->0K(9216K)] [ParOldGen: 0K->300K(10240K)] 352K->300K(19456K) [PSPermGen: 2848K->2847K(21504K)], 0.0111540 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
null
hello2
[GC [PSYoungGen: 327K->64K(9216K)] 627K->364K(19456K), 0.0004390 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC [PSYoungGen: 64K->0K(9216K)] [ParOldGen: 300K->300K(10240K)] 364K->300K(19456K) [PSPermGen: 2847K->2847K(21504K)], 0.0062450 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
hello2
解说:第一个hello对象,只被sr这个弱引用关联着,所以GC时可以被回收。
第二个hello2对象,它被str,和str2这两个引用关联着,而str是一个强引用,str2是一个弱引用;在文章开始就说过,如果一个对象被多个引用关联着,那么以最强的那个那个为主,所以GC回收时,并没有把hello2这个对象给回收了。
这里所说的被弱引用关联的对象是指只有弱引用关联一个对象,如果存在强引用与弱引用同时关联一个对象,则进行垃圾回收时也不会回收该对象(软引用也是如此)。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。
PhantomReference
PhantomReference,即虚引用,虚引用并不会影响对象的生命周期。虚引用的作用为:跟踪垃圾回收器收集对象这一活动的情况。
当GC一旦发现了虚引用对象,则会将PhantomReference对象插入ReferenceQueue队列,而此时PhantomReference对象并没有被垃圾回收器回收,而是要等到ReferenceQueue被你真正的处理后才会被回收。
注意:PhantomReference必须配合使用ReferenceQueue队列,其他引用可以使用队列,也可以不使用队列。
private static ReferenceQueue<Object> rq = new ReferenceQueue<Object>();
public static void main(String[] args){
PhantomReference<Object> pr = new PhantomReference<Object>(new Object(), rq);
System.out.println(pr.get());
System.gc();
System.out.println(pr.get());
Reference<Object> r = (Reference<Object>)rq.poll();
if(r!=null){
System.out.println(r.get());
System.out.println("回收");
}
}
输出结果:
null
[GC [PSYoungGen: 999K->352K(9216K)] 999K->352K(19456K), 0.0138740 secs] [Times: user=0.00 sys=0.00, real=0.02 secs]
[Full GC [PSYoungGen: 352K->0K(9216K)] [ParOldGen: 0K->300K(10240K)] 352K->300K(19456K) [PSPermGen: 2849K->2848K(21504K)], 0.0258600 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
null
null
回收
使用get是没有意义的因为源码里面是这样的:
public T get() {
return null;
}
PhantomReference的get总是返回为null。
PhantomReference也只有在你使用垃圾回收队列的时候它才会被回收,正常情况下不会被回收,但是你有获取不到对象,因为他总是返回null。
那么PhantomReference到底是用来干什么的呢?
它只是用来做对象回收跟踪的,类似一个GC跟踪器一样。我对象被回收了,啥时候被回收了,我跟踪一下它。
总结
Reference 有强,弱,软之分;弱,软,虚需要明确告诉vm,默认是强引用。一旦标记了为弱引用,那么vm在下一次GC时就会把对象给回收,其他的说明看上面的定义。这里用弱引用来说明一下。
GC前:
Reference r = new WeakReference(new byte[1024*1024], rq);
byte[] b= r.get();//b能获取到1M字节。
GC后
Reference r = new WeakReference(new byte[1024*1024], rq);
byte[] b= r.get();// b=null;
同时r被移到了队列里面去了。而我们程序可以通过rq队列来确定r是否被回收了。
如果没有队列rq。
GC前
Reference r = new WeakReference(new byte[1024*1024], null );
r.get();//能获取到1M字节。
GC后
Reference r = null;
//r.get();这个也不存在了。
这里想说明一下,我们在程序里面很少用到这些弱引用,软引用的,或者说用到了也只是使用new WeakReference(a, null );告诉vm,这个引用对我们不是很重要,你在GC时就可以把他回收了吧,不需要通知我了。如果你想让GC回收了对象后,通知你,那么你就传递一个new WeakReference(a, rq);rq队列进去,vm在GC你的对象后,他会发通知到rq队列面,而我们也可以去rq队列被GC的信息。
引用的强弱之分也可以说成引用的重要与否,定义为弱应用,就是告诉GC,这个引用对我不是很重要,你可以随时回收它的对象。
注意:这里回收的是对象,而不是引用;回收的是弱引用所引用的对象。
队列呢,就是让告诉GC,你把我的对象回收了,麻烦告诉我一声,把回收的对象的引用放到队列里面,让我知道一下。队列就好像是一个回调方法一样,让GC回调我们。
定义那么多引用类型,说到底就是为了利用GC的功能,帮我们做一些清除工作,同时也是帮助GC做一些回收决策。队列只是为了得到一个GC回收时通知我们一下而已,没了。
内存模型说明
Reference r = new WeakReference(new byte[1024*1024], rq);
r是一个符号引用,存入到了java内存的方法区。
new byte[1024*1024] new关键字所产生的是一个对象,存入到的是java内存的堆里面。GC发现没用任何类引用这个对象时就会它给回收了,就是把它从内存中清除了。
byte[] a = new byte[1024 * 1024];
a是一个强引用,当内存不够时,jvm会抛出OOM(内存溢出)。
Reference r = new WeakReference(new byte[1024 * 1024], rq);
r是一个软引用,不管jvm内存够不够,发生GC时都会被回收调。
GC回收是回收右边new 关键词产生的对象哦,左边的r,a只是一个符号引用而已哦,基本不占用内存的。
参考地址
http://blog.youkuaiyun.com/u010412719/article/details/52035792
http://blog.youkuaiyun.com/androidstar_cn/article/details/54710652
http://www.cnblogs.com/jabnih/p/6580665.html
http://www.cnblogs.com/absfree/p/5357689.html