引用包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被回收之后, 其对应的value也没有存在的意义了.

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

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

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

参考资料:

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值