前言: 看到篇帖子, 国外一个技术面试官在面试senior java developer的时候, 问到一个weak reference相关的问题. 他没有期望有人能够完整解释清楚weak reference是什么, 怎么用, 只是期望有人能够提到这个concept和java的GC相关. 很可惜的是, 20多个拥有5年以上java开发经验的面试者中, 只有两人知道weak reference的存在, 而其中只有一人实际用到过他. 无疑, 在interviewer眼中, 对于weak reference的理解和应用在面试中给了这一个interviewee相当多的加分. 所以, 将我对于这个技术的理解和使用总结在这篇博客里, 希望读者和自己通过读和写这篇帖子, 能够在以后的工作和面试中获益.
在Java里, 当一个对象o被创建时, 它被放在Heap里. 当GC运行的时候, 如果发现没有任何引用指向o, o就会被回收以腾出内存空间. 或者换句话说, 一个对象被回收, 必须满足两个条件: 1)没有任何引用指向它 2)GC被运行.
在现实情况写代码的时候, 我们往往通过把所有指向某个对象的referece置空来保证这个对象在下次GC运行的时候被回收 (可以用java -verbose:gc来观察gc的行为)
Object c = new Car(); c=null;
但是, 手动置空对象对于程序员来说, 是一件繁琐且违背自动回收的理念的. 对于简单的情况, 手动置空是不需要程序员来做的, 因为在java中, 对于简单对象, 当调用它的方法执行完毕后, 指向它的引用会被从stack中popup, 所以他就能在下一次GC执行时被回收了.
但是, 也有特殊例外. 当使用cache的时候, 由于cache的对象正是程序运行需要的, 那么只要程序正在运行, cache中的引用就不会被GC给(或者说, cache中的reference拥有了和主程序一样的life cycle). 那么随着cache中的reference越来越多, GC无法回收的object也越来越多, 无法被自动回收. 当这些object需要被回收时, 回收这些object的任务只有交给程序编写者了. 然而这却违背了GC的本质(自动回收可以回收的objects).
所以, java中引入了weak reference. 相对于前面举例中的strong reference:
Object c = new Car(); //只要c还指向car object, car object就不会被回收
当一个对象仅仅被weak reference指向, 而没有任何其他strong reference指向的时候, 如果GC运行, 那么这个对象就会被回收. weak reference的语法是:
WeakReference<Car> weakCar = new WeakReference(Car)(car);
当要获得weak reference引用的object时, 首先需要判断它是否已经被回收:
weakCar.get();
如果此方法为空, 那么说明weakCar指向的对象已经被回收了.
下面来看一个例子:
package weakreference; /** * @author wison */ public class Car { private double price; private String colour; public Car(double price, String colour){ this.price = price; this.colour = colour; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getColour() { return colour; } public void setColour(String colour) { this.colour = colour; } public String toString(){ return colour +"car costs $"+price; } }
package weakreference; import java.lang.ref.WeakReference; /** * @author wison */ public class TestWeakReference { public static void main(String[] args) { Car car = new Car(22000,"silver"); WeakReference<Car> weakCar = new WeakReference<Car>(car); int i=0; while(true){ if(weakCar.get()!=null){ i++; System.out.println("Object is alive for "+i+" loops - "+weakCar); }else{ System.out.println("Object has been collected."); break; } } } }
在上例中, 程序运行一段时间后, 程序打印出"Object has been collected." 说明, weak reference指向的对象的被回收了.
值得注意的一点, 即使有car引用指向对象, 且car是一个strong reference, weak reference weakCar指向的对象仍然被回收了. 这是因为java的编译器在发现进入while循环之后, car已经没有被使用了, 所以进行了优化(将其置空?).
当把TestWeakReference.java修改为:
package weakreference; import java.lang.ref.WeakReference; /** * @author wison */ public class TestWeakReference { public static void main(String[] args) { Car car = new Car(22000,"silver"); WeakReference<Car> weakCar = new WeakReference<Car>(car); int i=0; while(true){ System.out.println("here is the strong reference 'car' "+car);//use the strong reference in the while loop if(weakCar.get()!=null){ i++; System.out.println("Object is alive for "+i+" loops - "+weakCar); }else{ System.out.println("Object has been collected."); break; } } } }
weak reference指向的object就不会被回收了. 因为还有一个strong reference car指向它.
* WeakReference的一个特点是它何时被回收是不可确定的, 因为这是由GC运行的不确定性所确定的. 所以, 一般用weak reference引用的对象是有价值被cache, 而且很容易被重新被构建, 且很消耗内存的对象.
ReferenceQueue
在weak reference指向的对象被回收后, weak reference本身其实也就没有用了. java提供了一个ReferenceQueue来保存这些所指向的对象已经被回收的reference. 用法是在定义WeakReference的时候将一个ReferenceQueue的对象作为参数传入构造函数.
其他类型的references
-SoftReference
soft reference和weak reference一样, 但被GC回收的时候需要多一个条件: 当系统内存不足时(GC是如何判定系统内存不足? 是否有参数可以配置这个threshold?), soft reference指向的object才会被回收. 正因为有这个特性, soft reference比weak reference更加适合做cache objects的reference. 因为它可以尽可能的retain cached objects, 减少重建他们所需的时间和消耗.
-phantomReference
这个还没想到应用场景, 就先不说了. 有人在实践中用到了的话, 欢迎分享.
WeakHashMap
to be continued
相关推荐
Java 弱引用(WeakReference)的理解与使用 Java 中的弱引用(WeakReference)是一种特殊的引用类型,它可以帮助我们更好地管理内存和避免内存泄漏。在 Java 中,当一个对象被创建时,它被放在堆(Heap)中。当垃圾...
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。 弱引用(WeakReference)弱引用与软引用的区别在于:只...
Java编程语言以其强大的功能和广泛的应用在IT行业中占据了重要的地位,而面试时的Java问题往往能揭示应聘者对语言理解的深度和广度。"很容易弄错的Java面试题"通常涉及那些看似简单实则暗藏陷阱的问题,这些问题能够...
### Java面试知识点详解 #### 一、面向对象的三大特性 **封装**:是指将数据字段和操作这些字段的方法组织在一起形成一个整体的过程。通过封装,可以隐藏对象内部的复杂性和实现细节,使得外界只能通过有限的接口...
Java 面试题库 Java 是一种广泛使用的编程语言,它具有面向对象的设计原则、平台独立性、多线程支持等特点。本文档总结了 Java 面试题库,涵盖了 Java 语言的基础特性、面向对象设计原则、多线程、集合框架、反射、...
- 内存优化:使用内存分析工具识别内存泄漏,理解如何使用WeakReference和SoftReference。 - APK瘦身:减少资源冗余,压缩图片,混淆代码,优化APK大小。 7. **权限管理**: - 运行时权限:了解Android 6.0及...
对于刚入职场的Java小白和经验丰富的开发者来说,掌握集合框架的深入理解和使用至关重要。这份"Java集合面试,共52道题目"的资源,旨在帮助你全面了解和准备这方面的面试。 1. 集合框架概述: - 集合框架的基础是...
Java是一种广泛使用的面向对象编程语言,面试中常常会考察开发者对于Java基础知识的掌握程度。本题涉及了多个Java核心概念,包括面向对象的特性、多态性、接口、抽象类、不可变对象、变量类型、对象创建、字符串操作...
- Android组件间的通信:重点理解Intent的使用,包括隐式和显式Intent的区别与应用。 - Layout设计:掌握LinearLayout、RelativeLayout、ConstraintLayout等布局管理器的用法。 2. **Android进程和线程** - 进程...
- Handler、Looper、Message的理解与使用。 - AsyncTask的原理和限制,以及替代方案如RxJava、Coroutines。 - 线程池的使用与配置。 7. **数据存储**: - SharedPreferences、SQLite数据库、内部/外部存储、...
- 使用弱引用(WeakReference)来减少内存占用。 - 及时释放不再使用的资源,如关闭文件流、取消不必要的监听器等。 - 在适当的时候调用`System.gc()`强制垃圾回收,但应谨慎使用。 **10. Android四大组件** - **...
SoftReference、WeakReference和PhantomReference分析和比较 在 Java 中,引用类型分为强引用、软引用、弱引用和虚引用四种。强引用是我们最常用的引用类型,而软引用、弱引用和虚引用则是 Java 为我们提供的三种...
在IT行业中,尤其是在Android或Java开发中,弱引用(WeakReference)是一个重要的概念,它用于内存管理,防止内存泄漏。这个“WeakDelegate,Weakreference财产委托提议.zip”项目显然是一个Kotlin实现的开源项目,旨在...
- 使用WeakReference和SoftReference防止内存泄漏。 - 注意避免过度使用大对象,它们会直接进入Dalvik/ART的大对象区域,可能导致频繁的垃圾回收。 2. **UI优化**: - 使用ViewHolder设计模式优化ListView和...
4. **WeakReference与SoftReference**:两者都能帮助优化内存使用,但WeakReference的对象一旦失去所有强引用,就会立即被GC回收;而SoftReference的对象会在内存不足时才会被回收,提供了一种内存不足前的缓冲。 5...
Java中的四种引用类型是Java内存...Java中的引用类型给了我们控制对象生命周期的工具,通过合理使用不同类型的引用,可以有效地优化我们的程序性能,保证程序的稳定运行。同时,也加深了我们对Java内存管理机制的理解。
### Java基础面试题知识点解析 #### 一、面向对象的三个基本特征 - **封装**:将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类提供的方法来实现对内部信息的操作和访问。 - *...
以上只是《阿里Java开发手册_泰山版》的部分核心内容,该手册旨在引导开发者遵循良好的编程习惯,打造高质量的Java软件系统。通过遵循这些规范,可以有效地降低项目的维护成本,提高代码的可读性和可扩展性,从而...
以下根据标题“9套android经典面试题”和描述“值得将要面试的人好好参考”,我们将深入探讨这些面试题可能涵盖的知识点,帮助准备面试的Android开发者更好地理解并掌握核心概念。 1. **Android体系结构** - ...