利用C#实现标准的Dispose模式

GraphicsMagick之实践出真知 是个图片处理库,是从ImageMagick 5.5.2分支出来的,但是现在他变得更稳定和更轻、更快一些GraphicsMagick 号称图像处理领域的瑞士军刀。短小精悍的代码却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作,支持超过88种图像格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF。通过使用 OpenMP 可是利用多线程进行图片处理,增强了通过扩展 CPU 提高处理能力。 阅读详情
本文讲解的是你在建立包含内存以外资源的类型,特别是处置非内存资源的时候,如何编写自己的资源管理代码。

   我们已经知道了处置那些占用非受控(unmanaged)资源的对象的重要性,现在应该编写资源管理代码来处置那些包含非内存资源的类型了。整个.NET 框架组件都使用一个标准的模式来处理非内存资源。使用你建立的类型的用户也希望你遵循这个标准的模式。标准的处理模式的思想是这样的:当客户端记得的时候 使用IDisposable 接口释 放你的非受控资源,当客户端忘记的时候防护性地使用终结器(finalizer)。它与垃圾收集器(Garbage Collector)一起工作,确保只在必要的时候该对象才受到与终结器相关的性能影响。这是处理非受控资源的一条很好的途径,因此我们应该彻底地认识 它。

   类层次体系中的根基类(root base class)必须实现IDisposable 接口以释放资源。这个类型还必须添加一个作为防御机制的终结器。所有这些程序都把释放资源的工作委托给一个虚拟的方法,衍生的类可以根据自己的资源管理需求来重载该方法。只要衍生的类必须释放自己的资源,并且它必须调用该 函数的基类版本的时候,它才需要重载这个虚拟方法。

    开始的时候,如果你的类使用了非内存资源,它就必须含有一个终结器。你不能依赖客户端总是调用Dispose()方法。因为当它们忘记这样做的时候,你就 面临资源泄漏的问题。没有调用Dispose是它们的问题,但是你却有过失。用于保证非内存资源被正确地释放的唯一途径是建立终结器。

    当垃圾收集器运行的时候,它立即从内存中删除所有不带终结器的垃圾对象。所有带有终结器的对象仍然存在于内存中。这些对象都被添加到终结队列,垃圾收集器 引发一个新线程,周期性地在这些对象上运行终结器。在这些终结程序线程完成自己的工作之后,就可以从内存中删除垃圾对象了。需要终结的对象在内存中停留的 时间比没有终结器的对象停留的时间长很多。但是你别无选择。如果要使程序有防护性,在类型包含非受控资源的时候,你必须编写一个终结器。但是也不用担心性 能问题。下一步确保了客户端避免与终结相关的性能开销。
实现IDisposable 接口是一种标准的途径,它通知用户和运行时系统持有资源的对象必须及时地释放。IDisposable 接口仅仅包含一个方法:

public interface IDisposable
{
  void Dispose( );
}

   你对IDisposable.Dispose()方法的实现(implementation)负责下面四个事务:

   1、释放所有的非受控资源。

   2、释放所有的受控资源(包括未解开 事件)。

   3、设置标志表明该对象已经被处理过了。你必须在自己的公共方法中检查这种状态标志并抛出ObjectDisposed异常(如果某个对象被处理过之后再次被调用的话)。

   4、禁止终结操作(finalization)。你调用GC.SuppressFinalize(this)来完成这种事务。

   通过实现IDisposable 接口你完成了两个事务:你为客户端及时地释放自己持有的所有受控资源提供了机制;你为客户端提供了一种释放非受控资源的标准途径。这是一个很大的进步。当你在类型中实现了Idisposable 接口的时候,客户端可以避免终结操作的开销,你的类就成为.NET世界中的"良民"了。

    但是在你建立的这种机制中仍然存在一些问题。怎样在衍生类清理自己资源的时候同时也让基类能够清理资源?如果衍生类重载了终结操作,或者添加了自己的 IDisposable实现,那么这些方法必须调用基类,否则,基类就不能正确地进行清理操作。同样,finalize(终结操作)和Dispose参与 分担了一些相同的职责。Finalize方法和Dispose方法的代码几乎相同。而且在重载 接口 函数后并不像你预料的那样工作。标准的Dispose模式中的第三个方法是一个受保护的虚拟辅助 函数,它分解出这些共同的事务,并给衍生类添加一个用于释放资源的"钩子(hook)"。基类包含了核心 接口的代码。作为对Dispose()或终结操作的响应,该虚拟 函数为衍生类清除资源提供了"钩子":

protected virtual void Dispose( bool isDisposing );

    这个重载的方法实现支持finalize和Dispose的必要事务,由于它是虚拟的,它为所有的衍生类提供了一个入口点。衍生类可以重载这个方法,为清 除自己的资源提供适当的实现,同时还可以调用基类版本。当isDisposing为真(true)的时候,你可以清除受控和非受控资源,当 isDisposing为假(false)的时候,你只能清除非受控资源。在这两种情况下,你都可以调用基类的Dispose(bool)方法,让它清除 自己的资源。
   下面有一个简短的例子,它演示了你在实现这种模式的时候所提供的代码框架。MyResourceHog类演示了实现IDisposable 接口、终结器的代码,并建立了一个虚拟的Dispose方法:

public class MyResourceHog : IDisposable
{
  // 已经被处理过的标记
  private bool _alreadyDisposed = false;
  // 终结器。调用虚拟的Dispose方法
  ~MyResourceHog()
  {
   Dispose( false );
  }

  // IDisposable的实现
  // 调用虚拟的Dispose方法。禁止Finalization(终结操作)
  public void Dispose()
  {
   Dispose( true );
   GC.SuppressFinalize( true );
  }

  // 虚拟的Dispose方法
  protected virtual void Dispose( bool isDisposing )
  {
   // 不要多次处理
   if ( _alreadyDisposed )
    return;
   if ( isDisposing )
   {
    // TODO: 此处释放受控资源
   }
   // TODO: 此处释放非受控资源。设置被处理过标记
   _alreadyDisposed = true;
  }
}

   如果衍生类需要执行另外的清除操作,它应该实现受保护的Dispose方法:

public class DerivedResourceHog : MyResourceHog
{
  // 它有自己的被处理过标记
  private bool _disposed = false;

  protected override void Dispose( bool isDisposing )
  {
   // 不要多次处理
   if ( _disposed )
    return;
   if ( isDisposing )
   {
    // TODO: 此处释放受控资源
   }
   // TODO: 此处释放所有受控资源

   // 让基类释放自己的资源。基类负责调用GC.SuppressFinalize( )
   base.Dispose( isDisposing );

   // 设置衍生类的被处理过标记
  _disposed = true;
  }
}

   请注意,基类和衍生类都包含该对象的被处理过(disposed)标记。这纯粹是起保护作用。复制这个标记可以封装构成某个对象的所有类释放资源时产生的任何可能的错误。

    你必须编写防护性的Dispose和finalize。对象的处理可以按任意次序进行,你可能会遇到在调用自己类型的成员对象的Dispose()方法之 前,该对象已经被处理过了。你不应该认为这是问题,因为Dispose()方法会被多次调用。如果它在已经被处理过的对象上被调用,它就不执行任何事务。 Finalizer(终结器)也有类似的规则。如果你引用的对象仍然存在于内存中,你就没有必要检查空引用(null reference)。但是,你引用的任何对象都可能被处理了,它也可能已经被终结了。

   这为我带来了与处理或清除相关的任何方法的最重要的建议:你应该仅仅释放资源,在dispose方法中不要执行任何其它操作。如果你在Dispose或 finalize方法中执行其它操作,都可能给对象的生命周期带来严重的不良影响。对象在被构造的时候才"出生",当垃圾收集器收回它们的时候才"死亡 "。当你的程序再也不能访问它们的时候,你可以认为它们处于"昏睡"状态。如果你不能到达(reach)某个对象,你就不能调用它的方法,对于所有的意图 和目的来说,它是死的。但是带有终结器的对象被宣布死亡之前还有最后一口气。终结器除了清理非受控资源之外不应该执行其它任何操作。如果某个终结器由于什 么原因使某个对象又可以到达了,那么该对象就恢复(resurrected)了。即使它是从"昏睡"状态醒来的,它也是"活着"的。下面是一个很明显的例 子:

public class BadClass
{
  // 保存某个全局对象的引用
  private readonly ArrayList _finalizedList;
  private string _msg;

  public BadClass( ArrayList badList, string msg )
  {
   // 缓冲该引用
   _finalizedList = badList;
   _msg = (string)msg.Clone();
  }

  ~BadClass()
  {
   // 把该对象添加到列表中。这个对象是可到达的,不再是垃圾了。它回来了!
   _finalizedList.Add( this );
  }
}

    当某个BadClass对象执行自己的终结器的时候,它向全局列表上添加了对自己的引用。这仅仅使自己可到达了,它活了过来!但是这样操作所带来的问题使 任何人都会感到胆怯。该对象已经被终结了,因此垃圾收集器相信不用再次调用它的终结器了。你真的需要终结一个被恢复的对象的时候,终结操作却不会发生了。 其次,你的一些资源可能不能用了。GC不会把终结器队列中的对象可以到达的任何对象从内存中移除,但是它可能已经终结了这些对象。如果是这样的话,那些对 象一定不能再次使用了。尽管BadClass的成员仍然存在于内存中,它们却像被处理过或被终结了一样。在 C#语言中没有控制终结次序的途径。你不能使这种构造工作更可靠。不要尝试!

   除了学院的练习作业之外,我从来没有见到过如此明显地使用被恢复对象的代码。但是我看到有些代码有这个倾向,它们在终结器中试图执行某些实际工作,当终结器调用的某些 函数保 存了对该对象的引用的时候,它就正在把对象变成活动的状态。原则上我们必须非常仔细地检查finalizer和Dispose方法中任何代码。如果有些代 码除了释放资源之外还执行了其它的操作,我们就需要再检查一次。这些操作在未来可能引起程序bug。请移除这些操作,并确保finalizer和 Dispose()方法只释放资源,不作其它任务事务。

   在受控环境中,你不必为自己建立的每个类型编写终结器,你只需要为存储非受控类型,或者包含了实现IDisposable 接口的成员的类型编写终结器。即使你只需要Disposable 接口,不需要finalizer,也应该同时实现整个模式。否则,你会使衍生类的标准Dispose思想的实现变得很复杂,从而限制了衍生类的功能。请遵循前面谈到的标准的Dispose思想,这将使你、你的类的用户、从你的类型建立衍生类的用户的生活更加轻松。 
linux系统下XDMA驱动的安装与测试问题总结 先看两个常见的问题。一个是驱动安装问题,一个是驱动测试错误;error 512 能识别PCIE的设备,但是The kernel modle installed correctly, but no devices were recognized. 阅读详情

相关推荐

实战案例:用多智能体系统模拟房地产市场的架构设计

房地产市场是典型的复杂自适应系统:买方纠结“要不要上车”、卖方盘算“挂多少钱能快速成交”、中介忙着“撮合两边赚佣金”、政府琢磨“怎么调政策稳房价”——每一个参与者的微小决策,最终都会汇聚成“房价暴涨”“成交冰点”这样的宏观现象。传统的计量经济学模型(比如线性回归)假设“所有人都是理性人”,但现实中没人能算清所有变量——你可能因为“同事买了学区房”就跟风,也可能因为“怕失业”而放弃买房。这时候,多智能体系统(MAS)

移动开发前沿的博客 1122

C# 中的Dispose()用法

Dispose()    在向大家详细介绍C#调用Dispose()方法之前,首先让大家了解下Dispose()方法,然后全面介绍C#调用Dispose()方法。 我们已经知道了处置那些占用非受控(unmanaged)资源的对象的重要性,现在应该编写资源管理代码来处置那些包含非内存资源的类型了。整个.NET 框架组件都使用一个标准的模式来处理非内存资源。使用你建立的类型的用户也希望你遵循这个标准

JohnWang的专栏 2万+

图解转置卷积原理

声明:本文大部分搬运自【机器学习】详解 转置卷积 (Transpose Convolution) 感谢博主花与人间事同,本人只是在博主原创文章上做补充以及添加一些自己的理解。 1 转置卷积的背景 通常,对图像进行多次卷积运算后,特征图的尺寸会不断缩小。而对于某些特定任务 (如图像分割和图像生成等),需将图像恢复到原尺寸再操作。这个将图像由小分辨率映射到大分辨率的尺寸恢复操作,称为上采样 (Upsample),如下图所示: 上采样方法有很多,详见【图像处理】详解 最近邻插值、线性插值、双线性插值、双三次插值

laonafahaodange的博客 5685

C#实现标准的Dispose模式

上一章说过,对于对象包含非托管资源,要正确的加以清理。对于非托管资源来说,.net framework 会采用一套标准的模式来完成清理工作,因此,如果你编写的类里面用到了非托管资源,那么该类的使用者就会认为这个类同样遵循这套模式。标准的dispose(释放/处置)模式会处理IDisposable接口,又会提供finalizer(终结器/终止化器),以便客户端忘记调用IDisposeable.Dis...

西柚2015地信小白GISer 4811

保姆级教程:用YOLOv8n模型在RKNN和Horizon平台完成目标检测(附C++部署代码与性能实测)

本文提供了一份详尽的YOLOv8n模型在RKNN和Horizon平台上的部署指南,涵盖环境配置、模型优化、跨平台适配及性能调优。通过实战案例和C++部署代码,帮助开发者在嵌入式设备上高效实现目标检测,显著提升推理性能。

weixin_42659194的博客 468

SAP FICO实操:如何修改已发生业务数据的成本中心公司代码(附RKACOR06程序运行指南)

本文详细解析了SAP FICO系统中使用RKACOR06程序修改已发生业务数据的成本中心和公司代码的实操方法。通过实战案例分享,提供从前期准备到后期验证的全流程指南,帮助企业应对组织架构重组或财务核算体系调整时的数据迁移挑战,特别适用于跨公司代码的成本中心划转场景。

weixin_27303545的博客 189

dispose与close()的区别

Dispose了,就必须再Create一次而Close()后,还可以再Open(), 而Dispose后,对象都不存在了,就不能Open()了Dispose是对于对象自身而言的,Close是对于连接数据库而言的其它都是误导...  以下是相关知识点:1.SqlConnection conn = new SqlConnection(strConnection)时,如果原来的连接已经关闭,

cxzhq2002的杂记 2585

IP-Guard安全网关实例

企业相关情况: 1.OA系统,主要为日常工作使用,该系统IP为192.168.1.2,端口为8080; 2.文件共享服务器,用于存放日常工作资料和文档,该文件共享服务器的IP为192.168.1.1,其中\\192.168.1.1\private 目录中的存放着公司重要文档,不能随意外传; 3.安全网关已采用串联的方式联入网络,IP为192.168.2.6,所有机器访问OA系统和文件共享服务...

IP-Guard专栏 706

利用C#实现标准的 Dispose模式

本文讲解的是你在建立包含内存以外资源的类型,特别是处置非内存资源的时候,如何编写自己的资源管理代码。  我们已经知道了处置那些占用非受控(unmanaged)资源的对象的重要性,现在应该编写资源管理代码来处置那些包含非内存资源的类型了。整个.NET框架组件都使用一个标准的模式来处理非内存资源。使用你建立的类型的用户也希望你遵循这个标准的模式。标准的处理模式的思想是这样的:当客户端记得的时候使用ID

langhoo的专栏 758

ArcGIS JSAPI 高级教程 - 添加多个 box 立方体 - 通过顶点、索引、UV 自定义每个 box、每个面不同颜色

ArcGIS JSAPI 高级教程 - 添加多个 box 立方体 - 通过顶点、索引、UV 自定义每个 box、每个面不同颜色。

非科班Java出身GISer的博客 400

面向 Cloud Foundry、ABAP On-Prem 与 ABAP Cloud 的 SAP Fiori 开发全景:工具、流程与实战案例

SAP Fiori开发实战:基于BAS的一站式工程化方法 摘要: 本文系统梳理SAP Business Application Studio(BAS)在Fiori开发中的核心能力,提供三种典型后端(Cloud Foundry/ABAP On-Prem/ABAP Cloud)的对接方案。BAS通过预置Fiori Tools套件、MTA部署工具等扩展,支持从模板创建、可视化建模到构建部署的全流程。文章包含CAP+RAP服务对接、ABAP标准应用扩展等实战案例,重点解析注解驱动开发、Adaptation Proj

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 255

graphicsmagick和imagemagick对比

第一:打水印操作,串行执行 composite指令graphicsmagick转图的效率比imagemagick 的高,优化在20%,单张图片打水印graphicsmagick的处理用时随着并发数的递增变化不大,性能相对稳定,因此,随着并发数递增,graphicsmagick的转图性能比imagemagick 更优,高达30%。但公司图片上传用时,至少包括网络传图用时、磁盘读写用时、图片处理用时,测试单用户请求上传接口,graphicsmagick性能优化才5%。车型库编辑提供的实拍图片。

chyunling的专栏 1977

STM32F401RCT6最小系统原理图设计

STM32F401RCT6最小系统原理图设计一、主控芯片二、电源电路三、晶振电路三、下载电路四、完整电路图      本文章基于STM32F401RCT6进行最小系统原理图设计,包含主控芯片,电源,晶振电路,下载电路等几部分 一、主控芯片 主控芯片采用STM32F401RCT6,需注意: VBAT在不接电池的情况下需接3.3V,VDDAVREF+需接3.3V,否则会造成芯片供电不正常,无法启动和识别的情况 VDDAVREF+和VCAP1处电容需按照规格书

weixin_43278295的博客 2万+

图片工具GraphicsMagick的下载安装配置使用

转自http://www.kongzid.com/archives/tool1 , GraphicsMagick是一个短小精悍的图片处理工具和库集合。用来处理图像的读取、写入和操作,支持超过88中图像格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM、PhotoCD、SVG和TIFF。GraphicsMagick 是基于 ImageMagick 开发的。

孔子说 8610

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

GraphicsMagick介绍与安装

GraphicsMagick概述 简介 GraphicsMagick号称图像处理领域的瑞士军刀。 短小精悍的代码却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作,支持超过88中图像格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF。 通过使用OpenMP可是利用多线程进行图片处理,增强了

JairusChan的技术博客 5726

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

GraphicsMagick安装

1.基于centos安装GraphicsMagick 操作系统版本: centos6.9 64bit 1.1下载 图片处理需要系统中安装libpng和libjpeg的开发包,否则GraphicsMagick就没法读取jpeg和png图片。如果之前已安装过imageMagi...

chuimao5558的博客 688

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

GraphicsMagick介绍及安装

GraphicsMagick 当前稳定版本:1.3.12(发布日期2010-03-08) 简单介绍: GraphicsMagick号称图像处理领域的瑞士军刀。 短小精悍的代码却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作,支持超过88中图像格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF。 通过使用OpenMP可是...

aifeier1982的博客 256

ubuntu安装图片工具GraphicsMagick

GraphicsMagick 需要的依赖比较多不管用不用先装需要的一些依赖 - 一 zlib1g-dev zlib1g 在ubuntu软件源里zlib和zlib-devel叫做zlib1g zlib1g.dev $ sudo apt-get install zlib1g $ sudo apt-get install zlib1g.dev 直接输入上述命令后还是不能安装。这就要求我们先装...

wood-man的博客 1145

Linux 安装 GraphicsMagick

版本以及目录等配置,需要根据实际环境配置 1、gcc等编译工具的准备: yum install -y gcc gcc-c++ make cmake autoconf automake 2、这个一般的vps上都会有默认安装,检验是否已经安装可用如下命令: rpm -qa|grep gcc rpm -qa|grep make 3、libpng和libjpeg等图片...

phubing 1303

GraphicsMagick

[size=medium][b]简介[/b][/size] GraphicsMagick号称图像处理领域的瑞士军刀。 短小精悍的代码却提供了一个鲁棒、高效的工具和库集合,来处理图像的读取、写入和操作,支持超过88种图像格式,包括重要的DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF。 通过使用OpenMP可是利用多线程进行图片处理,...

lqwgy的博客 271

ubuntu安装GraphicsMagick

一、 sudo apt-get install graphicsmagick 二、 http://www.cnblogs.com/cocowool/archive/2010/08/16/1800954.html   基本步骤:   1、tar -xvzf GraphicsMagick-1.3.12.tar.gz   2、cd GraphicsMagick-1.3.12  

每一次对问题的深究,总会收获新的知识和体会 4138

GraphicsMagick的命令行使用示例

GraphicsMagick是从 ImageMagick 5.5.2 分支出来的,但是现在他变得更稳定和优秀,GM更小更容易安装、GM更有效率、GM的手册非常丰富GraphicsMagick的命令与ImageMagick基本是一样的。 [ convert | identify | mogrify | composite | montage | compare | display |...

MJKB123456的博客 235

GraphicsMagick在mac系统上的用brew的装配

Homebrew安装https://brew.sh/index_zh-cn.html ****************************************************** *   安装jpeg包 ****************************************************** sudo brew install libjpeg

maindek的博客 3200

GraphicsMagick简介及命令行使用示例

  GraphicsMagick简介及命令行使用示例   GraphicsMagick资料 ---------------------------------------------------------------------------- GraphicsMagick官网 GraphicsMagick编程接口 ImageMagick 程序接口   Im4java ...

stephen830 1229
上一篇: JavaScript技巧一则:使新建的浏览器窗口最大化
下一篇: Install assembly to GAC with VS Installer
forlinux
博客等级 码龄21年 53粉丝 95原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值