弱引用和弱事件

默認對象實例化後得到的都是強引用,不過有時候對於一些複雜的對象,出於性能考慮,并不希望進行頻繁的初始化,此時弱引用就可以派上用場。

用法:先用WeakReference包裝複雜對象,到需要該複雜對象的時候,檢查一下弱引用的IsAlive屬性,如果true,就可以通過Target直接得到複雜對象,省去了實例化的過程。

簡單的例子:

        static void Main(string[] args)
        {
            var weakRef = GetWeakRef();

            GC.Collect();

            if (weakRef.IsAlive)
            {
                var obj = weakRef.Target as ComplexObject;
                Console.WriteLine(obj);
            }
            else
            {
                Console.WriteLine("Reference is not available.");
            }

            Console.Read();
        }

        private static WeakReference GetWeakRef()
        {
            return new WeakReference(new ComplexObject());
        }

本例中如果調用了GC回收,輸出爲

Reference is not available.

如果不調用GC回收,輸出爲

ConsoleApplication1.ComplexObject

雖然都是弱,但弱事件的情形卻不太一樣,它的目的在於避免内存泄漏。

普通事件建立了一個發佈者到偵聽者之間的強引用,衹要發佈者存在,偵聽者就無法被回收,即使偵聽者已沒有存在的必要。

内存泄漏的一個簡單例子:

    class Publisher
    {
        public event EventHandler SomeEvent;

        public void RaiseEvent()
        {
            if (SomeEvent != null)
            {
                SomeEvent(this, EventArgs.Empty);
            }
        }
    }

    class Listener
    {
        public void Listener_SomeEvent(object sender, EventArgs e)
        {
            Console.WriteLine("SomeEvent happens");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var pub = new Publisher();
            var lsn = new Listener();

            pub.SomeEvent += lsn.Listener_SomeEvent;
            pub.RaiseEvent();

            lsn = null;
            GC.Collect();

            pub.RaiseEvent();

            Console.Read();
        }
    }   

程序輸出了兩次SomeEvent happens,説明lsn對象仍然保留在内存中,即使已經將其置空。

直接的解決辦法就是:偵聽者主動解除事件訂閲,沒了強引用,自然就可以回收了。 不過有時候難以確定解除事件的時機,此時弱事件就有用場了,它的訣竅在於引入第三方的管理器來間接關聯發佈者和偵聽者,這樣就不會在它們之間建立強引用,從而方便各自的回收。

不過相對於普通的事件偵聽者,弱事件下的偵聽者必須實現IWeakEventListener接口,如下:

   public class Publisher
    {
        public event EventHandler SomeEvent;

        public void RaiseEvent()
        {
            if (SomeEvent != null)
            {
                SomeEvent(this, EventArgs.Empty);
            }
        }
    }

   public class Listener : IWeakEventListener
    {
        public void Listener_SomeEvent(object sender, EventArgs e)
        {
            Console.WriteLine("SomeEvent happens");
        }

        public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            Listener_SomeEvent(sender, e);
            return true;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var pub = new Publisher();
            var lsn = new Listener();
            WeakEventManager<Publisher, EventArgs>.AddHandler(pub, "SomeEvent", lsn.Listener_SomeEvent);

            pub.RaiseEvent();

            lsn = null;
            GC.Collect();

            pub.RaiseEvent();

            Console.Read();
        }
    }

程序衹會輸出了一次SomeEvent happens,説明lsn確實被回收了。

时间: 2024-08-09 20:44:20

弱引用和弱事件的相关文章

Android中的WeakReference 弱引用

WeakReference 弱引用 定义:弱引用,与强引用(我们常见的引用方式)相对:特点是:GC在回收时会忽略掉弱引用对象(忽略掉这种引用关系),即:就算弱引用指向了某个对象,但只要该对象没有被强引用指向,该对象也会被GC检查时回收掉. 强引用实例自然不会被GC回收! 如何引出弱引用?弱引用的实际用途是什么? 什么是内存泄漏?Java使用有向图机制,通过GC自动检查内存中的对象:如果GC发现一个或一组对象为不可达的状态,则将该对象从内存中回收.也就是说:一个对象不被任何引用所指向,则该对象会在

Java 理论与实践: 用弱引用堵住内存泄漏---转载

要让垃圾收集(GC)回收程序不再使用的对象,对象的逻辑 生命周期(应用程序使用它的时间)和对该对象拥有的引用的实际 生命周期必须是相同的.在大多数时候,好的软件工程技术保证这是自动实现的,不用我们对对象生命周期问题花费过多心思.但是偶尔我们会创建一个引用,它在内存中包含对象的时间比我们预期的要长得多,这种情况称为无意识的对象保留(unintentional object retention). 全局 Map 造成的内存泄漏 无意识对象保留最常见的原因是使用 Map 将元数据与临时对象(trans

WeakReference(弱引用)

原地址:http://www.cnblogs.com/bayonetxxx/archive/2009/06/02/1494728.html 我们平常用的都是对象的强引用,如果有强引用存在,GC是不会回收对象的.我们能不能同时保持对对象的引用,而又可以让GC需要的时候回收这个对象呢?.NET中提供了WeakReference来实现.弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存.对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必

Java中的四种引用类型,强引用,软引用,弱引用,虚引用

对于Java中的垃圾回收机制来说,对象是否被回收的标准在于该对象是否被引用.因此,引用也是JVM进行内存管理的一个重要概念. Java中对象的引用一般有以下4种类型: 1强引用  2软引用  3弱引用  4虚引用 以下一一介绍其用法和区别 1强引用:在Java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用.当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收.因此强引用是造成Java内存泄漏的主

java强引用,软引用,弱引用,虚引用

用了Java怎么长时间一直不知道原来Java还有四种引用类型,这个引用类型和我们平常说的可不一样.这里的引用类型不是指数据类型的一种,而是指Java中的引用所分的四种类型.他们代表了JVM回收内存的四种强度,分别如下. 强引用: Java中的引用,有点像C++的指针.通过引用,可以对堆中的对象进行操作.在某函数中,当创建了一个对象,该对象被分配在堆中,通过这个对象的引用才能对这个对象进行操作. Object o=new Object(); 假设以上代码是在函数体内运行的,那么局部变量o将被分配在

关于C#中的弱引用

本文前部分来自:http://www.cnblogs.com/mokey/archive/2011/11/24/2261605.html 分割线后为作者补充部分. 一:什么是弱引用 了解弱引用之前,先了解一下什么是强引用 例如 : Object obj=new Object();     就是一个强引用,内存分配一份空间给用以存储Object数据,这块内存有一个首地址,也就是obj所保存的数据,内存分配的空间中不仅仅保存着Object对象信息,还保存着自己(Object本身)被引用的次数. 当一

C# 中的弱引用 WeakReference

C#中的弱引用(WeakReference) 我们平常用的都是对象的强引用,如果有强引用存在,GC是不会回收对象的.我们能不能同时保持对对象的引用,而又可以让GC需要的时候回收这个对象呢?.NET中提供了WeakReference来实现.弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存.对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必要时回收时,可以考虑使用弱引用.弱引用使用起来很简单,看下面的代码:Object obj =

Android性能优化之巧用软引用与弱引用优化内存使用

前言: 从事Android开发的同学都知道移动设备的内存使用是非常敏感的话题,今天我们来看下如何使用软引用与弱引用来优化内存使用.下面来理解几个概念. 1.StrongReference(强引用) 强引用是我们最最常见的一种,一般我们在代码中直接通过new出来的对象等,都是强引用,强引用只要存在没有被销毁,内存就不会被系统回收.我们以生成Bitmap为例如下: Bitmap imageBitmap = readBitmapFromResource(getResources(), R.mipmap

C#WeakReference弱引用

弱引用:在引用对象的同时,允许垃圾回收该对象. .NET中提供了WeakReference对象来实现这个功能. 对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用, 同时希望GC必要时回收时,可以考虑使用弱引用.弱引用使用起来很简单, WeakReference w = new WeakReference(xml);//创建若引用对象 if (w.IsAlive)//判断是否已被垃圾回收 { XmlDocument xml1 = w.Target as XmlDoc