`

WeakReference的理解和使用

 
阅读更多

引用自:http://blog.csdn.net/zmx729618/article/details/54093532 

 

看到篇帖子, 国外一个技术面试官在面试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);
			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, 减少重建他们所需的时间和消耗.

分享到:
评论

相关推荐

    WeakDelegate,Weakreference财产委托提议.zip

    - `LICENSE`: 开源许可协议,规定了项目使用和分发的条件。 6. **使用方法**:在实际项目中,开发者可能需要按照项目提供的说明,引入`WeakDelegate`类,然后在声明属性时使用该委托,例如: ```kotlin var ...

    详解Java弱引用(WeakReference)的理解与使用

    Java 弱引用(WeakReference)的理解与使用 Java 中的弱引用(WeakReference)是一种特殊的引用类型,它可以帮助我们更好地管理内存和避免内存泄漏。在 Java 中,当一个对象被创建时,它被放在堆(Heap)中。当垃圾...

    WPF MVVM视图绑定到单例和WeakReference

    在这个场景中,标题“WPF MVVM视图绑定到单例和WeakReference”涉及到两个关键概念:单例模式和弱引用。 首先,单例模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。在C#中,我们通常通过静态方法...

    android大位图二次采样处理三

    在Android开发中,大...开发者需要理解其原理,掌握计算采样率的方法,并结合最佳实践,如使用流式加载和第三方库,来优化位图处理,从而提升应用的性能和用户体验。同时,良好的内存管理和异常处理也是必不可少的。

    拓胜技术专家教你如何深入理解Java四种引用类型

    Java中的四种引用类型是Java内存管理的重要组成部分,它们分别是强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference)。每种引用类型具有不同的特点和用途,...

    android面试题.rar

    - Layout布局管理器:如LinearLayout、RelativeLayout、ConstraintLayout的使用和区别。 - View和ViewGroup:理解它们的关系,自定义View的实现。 - 动画:了解属性动画、帧动画和视图动画的区别及应用。 3. **...

    使用Android Studio检测内存泄露(LeakCanary)

    理解Android的内存管理机制和熟练使用这些工具,是提高应用性能和稳定性的重要一环。定期进行性能测试和内存分析,可以帮助开发者发现并修复潜在的问题,提升用户体验。记住,良好的编程习惯和对内存管理的深入理解...

    android面试宝典,全部弄会面试任何一家公司没问题

    - 内存优化:使用内存分析工具识别内存泄漏,理解如何使用WeakReference和SoftReference。 - APK瘦身:减少资源冗余,压缩图片,混淆代码,优化APK大小。 7. **权限管理**: - 运行时权限:了解Android 6.0及...

    教你写高效的android

    使用WeakReference和SoftReference来管理对象生命周期,避免内存泄露。 2. **线程和并发**:Android主线程负责UI更新,因此,理解多线程和异步处理至关重要。使用AsyncTask、Handler、Looper、Thread和Runnable来...

    用java代码实现的移除未使用资源。.zip

    有时我们希望对象在被垃圾回收之前保留一段时间,这时可以使用`WeakReference`和`SoftReference`。`WeakReference`的对象只要没有任何强引用指向它,就会被GC回收;而`SoftReference`的对象会在系统内存不足时才会被...

    Handler对象中使用匿名内部类或非静态内部类正确地释放消息避免内存泄漏或增加Native内存

    然而,不当使用Handler,尤其是结合匿名内部类或非静态内部类,可能导致内存泄漏和Native内存增加,这对应用性能和稳定性造成负面影响。 首先,我们要理解内存泄漏的概念。内存泄漏是指程序中已分配的内存没有被...

    十分钟理解Java中的弱引用编程开发技术共3页.pdf.z

    Java中的弱引用编程开发技术是Java内存管理的一个重要概念,对于优化内存使用和防止内存泄漏具有关键作用。本文将深入探讨这一主题,帮助你在这十分钟内建立起对弱引用的理解。 首先,我们需要知道Java的内存区域...

    Android面试宝典大全

    - 内存泄漏:识别和避免内存泄漏的方法,如使用WeakReference、SoftReference等。 - 内存优化:理解Dalvik/ART虚拟机的内存分配策略,如何进行内存分析和优化。 4. **Android权限管理** - 运行时权限:理解...

    C#面试基础问题

    - WeakReference:理解弱引用的概念,用于避免内存泄漏。 5. **高级主题** - 枚举和结构:比较枚举和结构的使用场景,以及它们的存储方式。 - 泛型:理解泛型类、泛型方法和约束,如List、Dictionary, TValue&gt;。...

    9套android经典面试题

    - XML布局文件的使用和优化。 - View和ViewGroup的绘制流程,了解MeasureSpec。 - 自定义View的基本步骤和注意事项。 3. **多线程与异步处理** - Handler、Looper、Message机制的运用。 - AsyncTask的优缺点...

    Android面试题整理

    理解弱引用(WeakReference)和软引用(SoftReference)的作用。 7. **性能优化**:了解如何通过ProGuard或R8进行代码混淆,提高应用的安全性和运行效率。探讨内存优化、绘制优化和启动速度优化的策略。 8. **多...

    android 学习示例

    6. 内存管理:如何避免内存泄漏,理解Activity的生命周期,以及如何合理使用WeakReference。 7. 文件存储:使用File、SharedPreferences或SQLite数据库进行数据存储的示例。 8. 第三方库集成:可能包含了如Glide、...

    Android程序员面试题精编版

    13. **内存管理和性能优化**:理解内存泄漏的概念,如何使用Profiler工具进行性能分析,以及如何通过避免不必要的对象引用和使用WeakReference防止内存泄漏。 14. **UI动画**:了解属性动画和视图动画的区别,以及...

    180个Android开发常见问题、实用技巧及注意事项

    同时,使用`WeakReference`和`SoftReference`管理对象,避免内存泄漏。 3. **性能调优**:使用`Systrace`和`Profile GPU Rendering`工具进行性能分析,找出应用中的瓶颈。优化UI绘制,确保不超过16ms的帧率,防止掉...

    Fragment与Activity使用Handler进行交互

    在Android应用开发中,Fragment和...正确理解和使用Handler能帮助开发者构建高效、稳定的Android应用程序。在实际开发中,还应结合其他通信方式,如Interface回调、EventBus、LiveData等,根据场景选择最适合的方法。

Global site tag (gtag.js) - Google Analytics