C#托管和非托管资源
一、基础概念
- 内存:程序运行于内存上,存储变量,函数,对象等数据,暂时存储CPU运算数据,
- 虚拟内存:
- 堆:也称托管堆,用于存储对象的数据结构,CPU无法直接读取
- 栈:用于存储变量的数据结构,CPU能直接读取
- 变量的生命周期:创建->使用->释放(该变量不在被使用,超过定义域范围)
- 对象的生命周期:
- 垃圾回收器:垃圾回收器运行时,会自动清理堆中不再引用的所有对象;通过调用System.GC.Collect()方法来强制执行垃圾回收,该方法常用于代码中有大量的对象刚取消引用时
- 托管资源:存放在堆上的对象,可由垃圾回收器回收
- 非托管资源:文件句柄、网络连接和数据库连接等成为非托管资源;
二、如何释放非托管资源
- 析构函数(终结器):频繁使用析构函数会影响性能
protected override void Finalize()
{
try
{
// Finalizer implementation
}
finally
{
base.Finalize();
}
}
- 继承IDisposable接口:该接口有一个Dispose()方法,Dispose()可以显式的释放对象所使用的非托管资源;如果在释放资源的过程中出现异常可以使用theInstance?.Dispose();来释放资源
ResourceGobbler theInstance = null;
try
{
theInstance = new ResourceGobbler();
// do your processing
}
finally
{
theInstance?.Dispose();
}
- using关键字:自动实现IDisposable接口,超过作用域自动调用Dispose()方法,且出现异常也会调用Dispose()方法
using (var theInstance = new ResourceGobbler())
{
// do your processing
}
- 析构函数与IDisposable接口双重组合
public class ResourceHolder : IDisposable
{
private bool _isDisposed = false;
public void Dispose()
{
Dispose(true);
//告诉垃圾回收器不要调用指定对象的Dispose方法,因为之前Dispose(true);已经做过了。防止两次执行。
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
// Cleanup managed objects by calling their
// Dispose() methods.
}
// Cleanup unmanaged objects
}
_isDisposed = true;
}
~ResourceHolder()
{
Dispose(false);
}
public void SomeMethod()
{
// Ensure object not already disposed before execution of any method
if (_isDisposed)
{
throw new ObjectDisposedException("ResourceHolder");
}
// method implementation…
}
}
四、不安全代码
- 指针:
1)优点:提高性能
2)缺点:编码和调试较为困难,无法通过CLR施加的内存类型安全检查 - unsafe关键字:用于编写不安全代码,为了保持类型安全,默认情况下,C# 不支持指针算法,因此C#只允许在特别标记的代码块中使用指针。
unsafe 在C# 程序中的使用场合:
1)实时应用,采用指针来提高性能;
2)引用非.net DLL提供的如C++编写的外部函数,需要指针来传递该函数;
3)调试,用以检测程序在运行过程中的内存使用状况。
使用unsafe 的利弊:
好处:性能和灵活性提高;可以调用其他dll的函数,提高了兼容性;可以得到内存地址;
坏处:非法修改了某些变量;内存泄漏。
unsafe 与unmanaged的区别:
managed code是在CLR监管下运行的程序。以下任务由CLR来执行:管理对象内存,类型安全检测和冗余处理。
unmanaged code也就是能由程序员直接进行内存操作的程序。
unsafe 是介于managed和unmanaged之间的桥梁,它使得managed code也能使用指针来控制和操作内存。
/*
表示假设所有的成员都是不安全的
*/
public unsafe class MyClass
{
// any method in this class can now use pointers
}
unsafe int GetSomeNumber()
{
// code that can use pointers
}
unsafe
{
}
unsafe int* pX;//pX必须为成员变量,不能把局部变量本身标记为unsafe
注:解决“不安全代码只会在使用 /unsafe 编译的情况下出现”方法,修改程序集属性。如上图所示
3.
参考链接:
C#学习之unsafe