当内存分配给应用程序时,应用程序有义务将该内存释放回操作系统,以便其他应用程序可以重新使用它。当应用程序不释放该内存从而阻止它被重新分配时,就会发生内存泄漏。
对于托管代码,垃圾收集器跟踪对应用程序创建的对象的引用。在大多数情况下,CLR 将代表正在运行的进程以合理的方式透明地处理内存分配和释放。然而,.NET 开发人员仍然需要考虑资源管理,因为尽管垃圾收集器的工作仍然存在内存泄漏的情况。
考虑以下代码:
Widget widget = new Widget();
上面的代码行创建了一个 Widget 类的新实例,并且为 widget 字段分配了对该对象的引用。 GC 跟踪与每个对象关联的引用,并释放没有强引用的对象的内存。
值得一提的是,CLR 的垃圾收集只会收集托管对象,.NET 代码可以并且确实经常使用无法自动进行垃圾收集的非托管资源。
当分配了这些资源的对象在对这些资源的最后一次引用超出范围之前未能正确解除分配时,就会发生非托管资源泄漏,这会留下已分配但未引用的资源,因此对应用程序不可用。
直接引用非托管资源的类应确保正确释放这些资源。执行此操作的示例如下所示:
public void ManagedObject : IDisposable
{
//A handle to some native resource.
int* handle;
public ManagedObject()
{
//AllocateHandle is a native method called via P/Invoke.
handle = AllocateHandle();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposing)
{
//deal with managed resources here
FreeHandle(handle);
}
}
~ManagedType()
{
Dispose(false);
}
}
disposing 参数在从终结器调用时为 false。这是为了防止在终结器中使用托管资源,因为托管引用在该阶段应被视为无效。
还要注意Dispose() 方法调用GC.SuppressFinalize(this) 这会阻止终结器为该实例运行。这样做是因为本来在终结器中释放的资源在 Dispose 调用中被释放,因此不需要终结器调用。
使用处理非托管资源的类(或任何实现 IDisposable 的类)的客户端代码应在 using 块中执行此操作,以确保在不再需要访问资源时调用 IDisposable.Dispose这将处理托管和非托管资源,并且在上面的示例中,确保不会对终结器进行非常昂贵的调用。
感谢我的漫无边际。我现在就停下来。