这两天, 广州的天气又开始热了起来, 又到了小动物交配的季节, 啊呸, 又到了一个收割 offer 的季节. 年底将至, 又到了面试的高峰期, JVM 作为 Java 程序员面试绕不过的一道坎儿, 它又来了, 你准备好了吗?
说说引用
面试官 A: 小伙几, 上篇我们说到了 JVM 收集的两种算法 -- 引用记数法和可达性分析算法, 你对这两种算法的理解很清晰, 那么这两种算法有一个很重要的点, 就是『引用』, 其实无论是引用记数法和可达性分析算法都离不开引用, 那么你来谈谈引用吧.
我: 这个啊, 简单, 引用 (reference) 就是一块内存存储着另一块内存地址(自信脸
面试官 A: 说的倒也没错, 但是过于片面, 那么你能不能详细讲一下引用呢?
我: 上白板, 我直接上图吧(熟练的拿起马克笔
面试官 A: 那么你能不能详细的说一下这四种引用是在什么情况下出现的呢, 它们分别代表了什么意义?
我: 先说说强引用吧, 我们日常中最常见到的就是强引用(拿起桌上的白板, 开始手写代码, 就像这样的, 就属于强引用, 它有多强呢, 就是只要强引用存在, GC 永远不会对它下手, 嗯, 你可以理解为就是范闲, 皇上的私生子.
- String s = "vi 的技术博客";
- s = "技不可失";
面试官 A: 你也看庆余年啊, 话说你看过原著没, 结局是什么给我剧透剧透呗.
我: 咳咳, 老哥这样不太好吧, 这是我的微信: cm_950825, 有什么咱们私聊好吧, 不要砸我 offer 收割机的招牌, 别人还以为我是靠裙带关系来着(小声 BB
面试官 A: 那你来说一下软引用吧.
我: 我们还是接着来聊庆余年吧, 开个玩笑啦, 我来一起把软引用和弱引用一起说吧, 它们都是用来描述一些非必需的对象, 但是弱引用比起软引用来说, 更加的弱, 怎么说呢, 还是看图吧(挥斥方遒的感觉
软引用关联的对象, 在系统发生 OOM 之前, 会把这些对象列入到回收范围之中进行二次回收, 如果这次回收仍然没有足够的内存, 才会发生 OOM, 它是长这样儿式儿的.
- Object o = new Object();
- SoftReference<Object> soft = new SoftReference<Object>(o);
而弱引用就是个弟弟, 只要有 GC, 必被回收, 这个弟弟是这样的
- Object o = new Object();
- WeakReference<Object> weak = new WeakReference<Object>(o);
而它们的有一个普遍的应用场景: 软引用和弱引用的一个特点是它何时被回收是不可确定的, 因为这是由 GC 运行的不确定性所确定的. 所以, 一般用它们是有价值被缓存, 而且很容易被重新被构建, 且很消耗内存的对象.
更深的东西我没有再去研究了..
面试官 A: 整挺好, 那你来说说最后的这个虚引用吧.
我: 虚引用啊, 这玩意儿你可以理解为没有这个东西, 它的唯一作用就是能在这个对象被 GC 的时候收到一个系统通知.
面试官 A: 是这样啊, 那行吧, 我手机没油了, 咱们下次接着聊
面试官上集手机忽然没油了, 不知道去哪加了一波油, 又回来准备继续和我大战三百回合, 尿遁用的如此熟练, 一看就不是第一次干这个事情, 不是个简单角色啊, 我需要提高警惕了.
继续面试
面试官 A : 刚刚我的手机没油了, 去加了点油(挑眉
我: 理解理解, 那咱们继续吧?
面试官 A: 刚刚我们说到关于引用的一些知识, 那么现在有一个问题, 我们最开始说到了『可达性分析法』是我们目前正在使用的一个判定方法, 那么是否没有连接到 GC Root 的对象都是被要被 GC 回收的呢?
我: 话其实也不能这么说 (捏衣角), 其实还是有挽回的余地的, 大道五十, 天衍四九. 自然会有一丝生机, 生机就在于 finalize() 这个神奇的方法中, 如果虚拟机发现对象没有连接到 GC Root 上, 这个对象就会被打上一个待回收的标签, 如果对它不管不顾, 它就会抛弃掉, 但是如果对它进行一些操作, 比如说重写 finalize() 方法, 在里面对它重新进行引用, 就可以对这个对象进行最后的救赎.
面试官 A: 既然说到了 finalize(), 你来说说你对这个方法的理解吧~
我: finalize()是 Object 类中的 protected 方法, 我们通常在子类中继承去完成资源清理的工作, GC 在进行回收的时候回去调用这个方法, 但是我们通常不会用这个方法去进行 GC, 而是去释放一些连接资源或者 IO 流.
面试官 A: 那么我们为什么通常不会用这个方法去完成 GC 呢?
我: 原因啊.. 这个我得好好想想, 是这样的, finalize()实际上并不能保证资源被回收, 因为对象的 finalize()方法中可以去做一些操作, 使对象重新活过来, 这个我刚刚也说过了, 而且, 由于 finalize()方法只会被执行一次, 会影响我们的判断, 而且它的运行效率非常低, 所以我们一般不会用 finalize()方法去回收对象.
面试官 A:OK, 虽然有些粗略, 但是大概说了出来, 最后一个问题, 你来梳理一下判定一个对象是否为垃圾的流程图吧.
我: 好嘞~
首先, 新建一个对象, 这个时候对象是处于存活状态的.
当对象变成 GC Roots 不可达的时候, GC 会去判断是否覆盖了 finalize()方法
如果没有覆盖, 直接进行回收.
如果覆盖了, 再去判断对象是否执行过 finalize()方法, 如果已经执行过, 那么也会进行回收.
如果覆盖且没有执行过 finalize()方法, 会将这个对象放到一个叫做 F-Queue 的队列中去.
稍后由一个 JVM 自动建立的, 低优先级的 Finalizer 线程去执行
这里需要注意: 这里的执行并不意味着真的会执行完毕, 只是告知虚拟机会触发这个方法, 并不保证可以运行完毕.
执行完毕之后, 如果对象仍然没有被重新引用(拯救), 那么就会被回收.
如果被重新引用的话, 就会被「复活」了.
面试官 A: 可以, 讲述的还算清楚, 我这边考虑一下, 你先回去等通知吧
我: 好的, 老哥再见~
公众号
来源: https://www.cnblogs.com/viyoung/p/12578999.html