java中持有引用 --- 引用包java.lang.ref

前言:

上次碰到个WeakHashMap,搞了一下,没明白, 碰到了引用包, 没太理解它的用处, 这次看JDK中Proxy的源码又碰到了,如鲠在喉, 一定要解决它

对象的回收过程:

标记阶段(此阶段, 一切工作必须停止, 如果有对象覆盖了finalize方法, 会先调用这个方法, 而暂时不做标记, 而推迟到下次gc的时候再做标记)

清理阶段(此阶段和工作可能并行进行)

这里大致为那些不懂gc的人解释一下:

标记阶段的主要任务就是寻找那些可以回收的对象(即不能通过你现有的所有引用直接或间接到达的对象), 这个阶段, 需要在JVM上面运行的程序暂停下来进行标记.

而清理阶段, 通常程序都不用暂停, 清理线程可以和程序并行执行, 因为他们所操作的内存并不相交.

引入引用包的目的, 就是把java中的常规引用标记为一种特定的引用, 在某些特定的情况下, gc可以对它进行回收, 而避免耗尽所有内存, 导致的JVM中常见的 OutOfMemoryError 错误的发生, 使得程序可以正常运转.

这种特殊的引用常用持有缓存的引用, 如将一个大图片放到内存中, 而避免从磁盘上读取, 当内存紧张时, 可以将其从内存中清除, 回收内存. 当再有需要时, 再将其读入内存.

如果是普通的java引用变量, 由于这个图片对象被引用, 所以一直都不会释放, 无法从内存中清除, 而用特殊的Reference来持有这个对象, 当你需要的时候, 你可以从Reference类中获取这个对象, 当这个对象被gc回收, Reference就会返回一个null, 这个时候, 你再加入额外的逻辑, 从磁盘中加载这个对象到内存中来.实现缓存的功能.

Reference下面有3个子类, 他们的回收时机各不一样:

SoftReference(合适做缓存)

当jvm把所有分配给他的内存都使用了,仍然不够, 那么gc就会收集软引用. 回收时(清除阶段), 软引用会被放入ReferenceQueue队列中, 并且解除它和引用对象的关联, 所以通过get()返回其所指向的引用对象时会null.
(将SoftReference放入ReferenceQueue对列是有原因的, 请看WeakHashMap部分)

WeakReference

和软引用类似, 区别在于gc发现WeakReference引用的对象时,就进行gc, 当在清除阶段时, 对象一旦清除, 就将其加入到ReferenceQueue中. 这时调用它的get()同样返回null

PhantomReference

这个和上面两个引用不同在于, 当它引用的对象一旦被gc发现,就会进行回收, 不过在清除之前,会现将其放入ReferenceQueue队列, 而不是等到引用对象的内存被清除了才放入. 它的get()方法始终返回null.
(get()方法始终返回null也是有原因的, PhantomReference常被用作finalize的一个替代品, 原因见下面的解释)

Why PhantomReference?

让通知更加精准, 即在finalize之后, 内存回收之前. 而不是只在finalize中.
用 finalize的时候, 首先发现此对象不可及, 为了避免此对象在finalize方法中把this赋给一个强引用造成的复活,而错误被收集的情况, gc不会在调用finalize之后立即清除此对象, 而是会在第二次gc的时候清除其内存.当内存很少, 很快就要OutOfMemoryError发生时, 这种等待是致命的, 而虚引用就没这种缺点, 一次gc即可收集.在标记阶段, 如果发现此虚引用的对象不可及了, 那么就加入队列, 在清理阶段就一次性回收了. (注意, 标记阶段是同步的, 清理阶段是异步的)

Why ReferenceQueue?

为什么要在引用们所指向的referent被gc之后, 要把引用加入到ReferenceQueue之中呢?
想象一下, 如果你将WeakReference<key>放入Map中,而不是key直接放入map中.那么当key只被WeakReference引用时,这个对象就会被gc回收, 当key被回收之后, 其对应的也没有存在的意义了. 

怎么才能知道这个key被回收了呢? 
只有知道key被回收了, 我们就能及时的清除, 减少内存的消耗.

简单, 因为一旦key被清除, WeakReference就会被放入ReferenceQueue, 你可以从ReferenceQueue中找到它, 并将其作为key, 去Map中索引, 用remove方法将其移除.

而 WeakHashMap就是帮你自动实现了这个Map<WeakReference<key>, >的类, 现在你再也不需要用WeakReference<key>作为key了, 你可以直接将key放入其中, WeakHashMap<key, >会自动为你做上述一切工作.

参考资料:

1. 理解弱引用
http://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html

2. 引用类使用指南
https://www.ibm.com/developerworks/cn/java/j-refs/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值