说说WeakReference弱引用

本文深入探讨Java中的弱引用(WeakReference)概念及其应用场景,并通过示例代码展示弱引用的工作原理,帮助理解垃圾回收机制。


WeakReference弱引用概述

http://www.cnblogs.com/xrq730/p/4836700.html,关于Java的四种引用状态具体请参看此文

Java里一个对象obj被创建时,被放在堆里。当GC运行的时候,发现没有任何引用指向obj,那么就会回收obj对象的堆内存空间。

但是现实的情况时,写代码的时候,往往通过把所有指向某个对象的引用置空来保证这个对象在下次GC运行的时候被回收:

Object obj = new Object();

obj = null;

这种方式说可以吧,也不是不可以,但是对于程序员来说,这是一件繁琐而且未被自动回收理念的。手动置空不应该需要程序员来做的,因为对于一个简单的对象而言,当调用它的方法执行完毕,引用会自动从栈中弹出,这样下一次GC的时候就会自动回收这块内存了。

但是有例外。比如说缓存,由于缓存对象是程序需要的,那么只要程序正在运行,缓存中的引用是不会被GC的,随着缓存中的引用越来越多,GC无法回收的对象也越来越多,无法被自动回收。当这些对象需要被回收时,回收这些对象的任务只有交给程序员了,然而这却违背了GC的本质----自动回收。

所以Java中引入了弱引用WeakReference。

 

WeakReference弱引用示例

下面演示一下WeakReference简单的使用,首先定义一个实体类:

复制代码
public class Car
{
    private double     price;
    private String    color;
    
    public Car(double price, String color)
    {
        this.price = price;
        this.color = color;
    }
    
    public double getPrice()
    {
        return price;
    }

    public String getColor()
    {
        return color;
    }

    public String toString()
    {
        return "This car is a " + this.color + " car, costs $" + price;
    }
}
复制代码

一般使用WeakReference的时候都会定义一个类继承自WeakReference,在这个类中再定义一些别的属性,这里就不定义别的属性了:

复制代码
public class WeakReferenceCar extends WeakReference<Car>
{
    public WeakReferenceCar(Car car)
    {
        super(car);
    }
}
public class WeakReferenceCar extends WeakReference<Car>
{
    public WeakReferenceCar(Car car)
    {
        super(car);
    }
}
复制代码

main函数调用一下,当然为了更清楚地看到GC的效果,设置虚拟机参数"-XX:+PrintGCDetails":

复制代码
public static void main(String[] args)
    {
        Car car = new Car(2000.0, "red");
        WeakReferenceCar wrc = new WeakReferenceCar(car);
        wrc.setStr("111");
        int i = 0;
        while (true)
        {
            if (wrc.get() != null)
            {
                i++;
                System.out.println("WeakReferenceCar's Car is alive for " + i + ", loop - " + wrc);
            }
            else
            {
                System.out.println("WeakReferenceCar's Car has bean collected");
                break;
            }
        }
    }
复制代码

看一下运行结果:

复制代码
WeakReferenceCar's Car is alive for 22880, loop - com.xrq.test14.WeakReferenceCar@5d888759
WeakReferenceCar's Car is alive for 22881, loop - com.xrq.test14.WeakReferenceCar@5d888759
WeakReferenceCar's Car is alive for 22882, loop - com.xrq.test14.WeakReferenceCar@5d888759
WeakReferenceCar's Car is alive for 22883, loop - com.xrq.test14.WeakReferenceCar@5d888759
WeakReferenceCar's Car is alive for 22884, loop - com.xrq.test14.WeakReferenceCar@5d888759
[GC [PSYoungGen: 16400K->256K(18688K)] 16400K->256K(61440K), 0.0002863 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
WeakReferenceCar's Car is alive for 22885, loop - com.xrq.test14.WeakReferenceCar@5d888759
WeakReferenceCar's Car has bean collected
Heap
 PSYoungGen      total 18688K, used 899K [0x0000000034180000, 0x0000000035650000, 0x0000000048f80000)
  eden space 16064K, 4% used [0x0000000034180000,0x0000000034220c30,0x0000000035130000)
  from space 2624K, 9% used [0x00000000353c0000,0x0000000035400000,0x0000000035650000)
  to   space 2624K, 0% used [0x0000000035130000,0x0000000035130000,0x00000000353c0000)
 PSOldGen        total 42752K, used 0K [0x000000000a580000, 0x000000000cf40000, 0x0000000034180000)
  object space 42752K, 0% used [0x000000000a580000,0x000000000a580000,0x000000000cf40000)
 PSPermGen       total 21248K, used 3016K [0x0000000005180000, 0x0000000006640000, 0x000000000a580000)
  object space 21248K, 14% used [0x0000000005180000,0x0000000005472318,0x0000000006640000)
复制代码

看到22884次循环之后,WeakReferenceCar关联的对象Car被回收掉了,注意是弱引用关联的对象car被回收,而不是弱引用本身wrc被回收。

 

其他

1、除了弱引用,还有软引用。SoftReference(软引用)和WeakReference的区别在于,假如下次GC的时候,发现内存没有溢出,则不会回收SoftReference关联的对象,但是对于WeakReference,在下一次GC的时候,一定会回收,无论内存是否满。像缓存,其实最适合的个人认为应该是SoftReference,因为缓存里面的数据是运行时会用到的,能不回收就尽量不要去回收它们,而等到内存实在不够的时候再去回收

2、WeakReference的父类Reference中有一个变量queue,是ReferenceQueue类型的。WeakReference中的构造函数中有一个两个参数的构造函数,其中第二个参数就是这个ReferenceQueue,表示在WeakReference指向的对象被回收之后,可以利用ReferenceQueue来保存被回收的对象

### WeakReference弱引用 WeakReference 是一种特殊的引用类型,其作用在于避免对对象的强引用,从而使对象在没有其他强引用时可以被垃圾回收器回收。在弱事件模式中,使用 WeakReference 能够避免订阅者被强引用,进而防止因事件订阅导致对象无法被回收的问题。 ### WeakEventManager弱事件 WeakEventManager 是用于实现弱事件模式的机制。在 .NET 中,特别是在 WPF 框架里有相关的类来实现此机制。WPF 框架自带的 WeakEventManager 功能有限,继承实现难度高,但性能高,WPF 绑定等机制的底层实现会用到该类型;而 WPF 框架自带的泛型类 WeakEventManager<TEventSource, TEventArgs> 能让开发者更容易实现自己的弱事件,不过性能较差 [^2]。 WeakEventManager 在实现时会使用 ConditionalWeakTable,它能将处理程序(委托)的生命周期与目标对象的生命周期相关联。以 Windows Presentation Foundation 中的 WeakEventManager 类为例,就借助 ConditionalWeakTable 把事件处理程序和事件源对象关联起来,当事件源对象被垃圾回收时,对应的事件处理程序也不会阻碍其回收 [^3]。 以下是一个简单的 C# 代码示例,展示如何使用弱引用和弱事件管理: ```csharp using System; using System.Windows; using System.Windows.Threading; // 事件参数类 public class CustomEventArgs : EventArgs { public string Message { get; set; } } // 事件发布者类 public class EventPublisher { public event EventHandler<CustomEventArgs> CustomEvent; public void RaiseEvent() { CustomEvent?.Invoke(this, new CustomEventArgs { Message = "Event raised!" }); } } // 事件订阅者类 public class EventSubscriber { public void HandleEvent(object sender, CustomEventArgs e) { Console.WriteLine($"Received message: {e.Message}"); } } class Program { static void Main() { EventPublisher publisher = new EventPublisher(); EventSubscriber subscriber = new EventSubscriber(); // 使用 WeakEventManager 订阅事件 WeakEventManager<EventPublisher, CustomEventArgs>.AddHandler(publisher, "CustomEvent", subscriber.HandleEvent); publisher.RaiseEvent(); // 模拟垃圾回收 subscriber = null; GC.Collect(); GC.WaitForPendingFinalizers(); publisher.RaiseEvent(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值