知识大全 未释放事件Handler可能导致内存泄漏

Posted 事件

篇首语:敢说敢作敢为, 无怨无恨无悔。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 未释放事件Handler可能导致内存泄漏相关的知识,希望对你有一定的参考价值。

未释放事件Handler可能导致内存泄漏  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  以前曾看见过这样一个问题 托管代码会不会导致内存泄漏 自己对GC的了解也不是很深 但还是比较赞成这样的观点 托管代码不会产生内存泄漏 除非你没有正确释放非托管资源

  今天看到一个非常有趣的例子 关于没有释放事件的Handler导致的内存泄漏

  以前对于释放Handler的观念是一点也没有 这主要因为没此方面的意识 没有养成好的习惯 只知道当关心这个事件的时候就注册一下 暂时不关心了就移除掉 却从来没有想到最终不移除不必要的Handler会导致此类无法被正常回收 导致不必要的内存浪费

  事情是这样的 今天在看项目Source Code的时候发现一个有趣的字眼 WeakEvent 自己以前对WeakReference有点了解 所以就好奇地看看这是个啥玩意

  发现其是一种通过弱引用实现的Delegate 因为没有太多的注释 所有不知其为啥用此种方式来封装事件 于是顺手Google了一下 找到了一篇关于weak event的非常有意思的文章

  文章里提出了一个问题 场景如下

  UnRelease Event Handler

  using System

  using System Collections Generic

  using System Text

  using Microsoft Win

  namespace ConsoleApplication

  

  class DisplaySettingsListener

  

  byte[] m_ExtraMemory = new byte[ ]

  public DisplaySettingsListener()

  

  SystemEvents DisplaySettingsChanged += new EventHandler(ehDisplaySettingsChanged)

  

  private void ehDisplaySettingsChanged(object sender EventArgs e)

  

  

  

  class Program

  

  static void DisplayMemory()

  

  Console WriteLine( Total memory ### ### ### ## bytes GC GetTotalMemory(true))

  

  static void Main()

  

  DisplayMemory()

  Console WriteLine()

  for (int i = i < i++)

  

  Console WriteLine( —— New Listener # —— i + )

  DisplaySettingsListener listener = new DisplaySettingsListener()

  listener = null

  GC Collect()

  DisplayMemory()

  

  Console Read()

  

  

  

  运行的结果如下

   

  虽然我们释放了对listener的引用 并且强制GC进行回收 但我们可以看到其内存占用量还是变大了 出乎了我的意料

  这就是该文作者指出的事件列表里保存的是一个强命名的引用而非弱引用 虽然上面释放了listener变量对Listener实例的引用 但因为仍然在DisplaySettingsChanged事件列表里保存了对Listener实例的引用 导致Listener实例并不能被垃圾回收(有人引用 自然不会回收)

  那么接下来看看下面的代码

  Release Event Hanlder

  class DisplaySettingsListener IDisposable

  

  byte[] m_ExtraMemory = new byte[ ]

  public DisplaySettingsListener()

  

  SystemEvents DisplaySettingsChanged += new EventHandler(ehDisplaySettingsChanged)

  

  private void ehDisplaySettingsChanged(object sender EventArgs e)

  

  

  IDisposable Members#region IDisposable Members

  public void Dispose()

  

  SystemEvents DisplaySettingsChanged = new EventHandler(ehDisplaySettingsChanged)

  

  #endregion

  

  class Program

  

  static void DisplayMemory()

  

  Console WriteLine( Total memory ### ### ### ## bytes GC GetTotalMemory(true))

  

  static void Main()

  

  DisplayMemory()

  Console WriteLine()

  for (int i = i < i++)

  

  Console WriteLine( —— New Listener # —— i + )

  DisplaySettingsListener listener = new DisplaySettingsListener()

  listener Dispose()

  listener = null

  GC Collect()

  DisplayMemory()

  

  Console Read()

  

  

  运行结果如下

   

  结果是不是正如您猜测的呢 ) 已经成功地回收了listener实例 不知为何从 字节变到 字节 哪位高手赐教一下啊 )

  详情可以看原文 The Problem With Delegates

  在后续的文章中作者类似文章开头提到的Weak Event来解决这个问题 Solving the Problem with Events Weak Event Handlers

cha138/Article/program/net/201311/11737

相关参考

知识大全 Java内存泄漏调试

Java内存泄漏调试  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  JDK本身为调试内存泄漏问题

知识大全 Java 程序里的内存泄漏

Java程序里的内存泄漏  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java程序里的内存泄漏

知识大全 Java内存泄漏分析与解决方案

Java内存泄漏分析与解决方案  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Java内存泄漏是

知识大全 DataTable.NewRow 内存泄漏问题

DataTable.NewRow内存泄漏问题  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  先看

知识大全 我的手机能下载但不能安装,老是显示未安装应用程序应该怎么办

我的手机能下载但不能安装,老是显示未安装应用程序应该怎么办您好:根据您描述的情况,有可能是以下几方面:1.手机内存不足导致软件不能正常安装,建议您将手机内存储的多媒体文件移动至外置SD卡中扩展手机内存

知识大全 解析PHP中的内存管理,PHP动态分配和释放内存

解析PHP中的内存管理,PHP动态分配和释放内存  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!本篇

知识大全 java内存泄漏的定位与分析

  ArrayList就是传说中的动态数组就是Array的复杂版本它提供了如下一些好处动态的增加和减少元素灵活的设置数组的大小……  认真阅读本文我相信一定会对你有帮助比如为什么ArrayList里面

知识大全 释放内存时怎样确保小米手环一直在后台运行

释放内存时怎样确保小米手环一直在后台运行释放内存时为了确保小米手环一直在后台运行,可按如下步骤进行:在手机中运行小米手环,返回桌面,确保小米手环此时正在后台运行,长按home键,此时会出现后台运行的程

知识大全 解析PHP中的unset究竟会不会释放内存

解析PHP中的unset究竟会不会释放内存  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!PHP中的

近40年全球严重石油泄漏事件

1967年3月,利比里亚油轮“托雷峡谷”号在英国锡利群岛附近海域沉没,12万吨原油倾入大海,浮油漂至法国海岸。