非托管资源

IDisposable的接口是用来手动释放非托管资源,换另一句话说,释放非内存(非托管)资源。内存资源因为垃圾回收保证回收,但非内存资源(如socket, 文件handle等)的数量比内存少,占用多也不一定触发垃圾回收,因此需要手动及时清理。基本上在.NET中,如果一个类使用了非内存资源,它都会实现一个IDisposable接口。如果不手动调用Dispose方法,那么当这个类对象被垃圾回收时,.NET会调用类对象的析构方法,通知类对象释放非内存资源。所以垃圾回收可以保证非托管资源的回收,但时效性差。一个占用socket的对象要等垃圾回收机制来回收socket资源,那么系统的吞吐量肯定差。从上面的描述可以看出来,非托管资源的回收时机有两个,一个是手动(IDisposable接口),一个是自动(垃圾回收调用的析构器)。


4常见内存问题

4.1使用了非托管资源的类

非托管资源的类是指本身是被CLR管理的,而且其管理的非托管资源也可以被CLR自动回收,因为CLR只能跟踪非托管资源的生存期,但是不能主动去做GC,所以GC的时机不确定,所以在使用完后应及时释放。

例如:调用FileStream

 FileStream file = new FileStream(@"c:\Test.txt", FileMode.Open);   

连续两次调用程序会报“文件正在使用中”的异常,如果两次调用中间调用强制回收,则不会报异常。

再例如:使用ODP.NETOracleCommandOracleDataReader,在Close后还需要Dispose;

OracleCommand cmd = new OracleCommand();

cmd.CommandText = sbSQL.ToString();

cmd.Connection = conn;

cmd.Parameters.Add(p1);

OracleDataReader dr = cmd.ExecuteReader();

if (dr.Read())
{
//…
dr.Close();
}
else
{
}
dr.Dispose();
cmd.Dispose();

常见的使用了非托管资源的类如下:

ApplicationContextComponentComponentDesigner
BrushContainerContext
CursorFileStreamDataSet
FontIconImage
MatrixTextureOdbcDataReader
OleDBDataReaderPenRegex
SocketStreamWriterTimer
TransactionDataReaderPing
TooltipBitmapSerialPort

以上列出的类均继承了IDisposable接口,需要在使用完后调用Dispose方法释放或者使用Using语句块,比如DataTableDataSetDataReaderTransactionBitMap

4.2 Win32API及COM

指通过本地API函数与托管对象进行交互(比如:通过 P/Invoke方式调用本地DLL,DLLImport声明静态外部函数和COM Interop)所用到的非托管资源。

例如:当通过DLL Import调用 API函数GetDC函数时忘了调用ReleaseDC去释放设备句柄造成4个字节的内存泄漏。

再如:智能文档中使用的Word以及导出EXCEl功能用到的Office的COM非托管组件,在关闭时GC不能识别COM组件而造成有时候无法对COM对象进行释放,这时候可以通过以下两个InteropServices函数进行释放

System.Runtime.InteropServices.Marshal.ReleaseComObject(comObject);

递减与指定的 COM 对象关联的指定 运行时可调用包装 (RCW) 的引用计数。

返回值为关联的 RCW 的引用计数的新值。此值通常为零,因为无论调用包装 COM 对象的托管客户端有多少,RCW 仅保留对该对象的一次引用。

所以通过这个方法显式的通过CLR释放非托管 COM 对象上的所有引用。

System.Runtime.InteropServices.Marshal.FinalReleaseComObject(comObject);

通过将 运行时可调用包装 (RCW) 的引用计数设置为 0,释放对它的所有引用。

返回值为与 comObject参数关联的 RCW 的引用计数的新值,如果释放成功,则为 0(零)。

4.3事件造成的内存泄漏

当不需要使用事件时,应退订事件,为了确保安全可以在Dispose方法中退订事件.

当对象不再触发事件时,应该将对象设为null来移除所有的事件订阅者

4.4动态添加生成控件造成内存泄漏

动态生成引用了非托管资源的控件后,注意一定要Dispose();

例如:

RichTextBox rtb = new RichTextBox();

frm.Controls.Add(rtb);

frm.Controls.Remove(rtb);

rtb.Dispose();
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值