NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次您使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行库就会继续为新对象分配空间。但是,内存不是无限大的。最终,垃圾回收器必须执行回收以释放一些内存。垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存。 本节介绍了垃圾回收器如何自动管理应用程序中托管对象的内存分配和释放。除此之外,本节还介绍了推荐的设计模式,以用来正确地清理应用程序创建的任何非托管资源。
1、开发人员在内存管理方面的背景
介绍了惯常使用 Visual Basic、C++ 和 COM 的开发人员在转向使用托管代码时应该进行的调整。
根据您开发背景的不同,您在内存管理方面的经验也会有所不同。在某些情况下,您可能需要让您的编程习惯来适应公共语言运行库提供的自动内存管理。
COM 开发人员
COM 开发人员习惯于将实现引用计数作为一个手动的内存管理技术。每次引用一个对象,计数器就递增。如果对对象的引用超出了范围,计数器就递减。当对象的引用计数达到零时,对象被终止并释放其内存。
引用计数方案会引发许多调试错误。如果未能严格地按照引用计数的规则进行操作,对象可能被过早释放或者未引用的对象积存在内存中。循环引用也是常见的问题根源。循环引用出现在子对象引用父对象,而父对象又引用子对象时。这种情况使两个对象都不能被释放或销毁。唯一的解决方案就是让父对象和子对象都遵守一个固定的使用和销毁模式,例如总是先由父对象删除子对象。
当使用面向公共语言运行库的语言开发应用程序时,运行库的垃圾回收器不用对引用进行计数,因此也就避免了由这种手动管理内存方案引发的错误。
C++ 开发人员
C++ 开发人员熟悉与手动内存管理相关的任务。在 C++ 中,当您使用 new 运算符为对象分配内存时,您必须使用 delete 运算符释放对象的内存。这可能导致多种错误,例如忘记释放对象、引起内存泄漏或试图访问已被释放的对象的内存。
当使用 C++ 的托管扩展或面向公共语言运行库的其他语言开发应用程序时,您就不必使用 delete 运算符释放对象了。垃圾回收器在当对象不再被应用程序使用时自动为您完成这些操作。
考虑到手动管理短期对象内存的相关成本,C++ 开发人员可能习惯于避免使用这些对象。对于两次回收间创建的然后又不再使用的托管短期对象,分配和释放内存的成本非常低。在 .NET Framework 中,实际上已经对垃圾回收器进行了优化来管理具有较短生存期的对象。当开发托管应用程序时,在短期对象可以简化代码的情况下使用它们是非常合适的。
Visual Basic 开发人员
Visual Basic 开发人员习惯于自动内存管理。您熟悉的编程惯例将应用于您在 .NET Framework 中创建的大多数托管对象。但是,当创建或使用封装非托管资源的对象时,您应该特别注意使用 Dispose 方法的推荐设计模式。
.NET Framework 支持的面向公共语言运行库的语言要比在此介绍的语言多。不管您使用哪一种托管语言,.NET Framework 的垃圾回收器都提供自动内存管理。它为托管对象分配和释放内存,并在必要时执行 Finalize 方法和析构函数来适当地清理非托管资源。自动内存管理通过消除手动内存管理方案引起的常见问题简化了开发。
2、Finalize 方法和析构函数
介绍 Finalize 方法和析构函数如何允许对象在垃圾回收器自动回收对象的内存之前执行必要的清理操作。
对于您的应用程序创建的大多数对象,可以依靠 .NET Framework 的垃圾回收器隐式地执行所有必要的内存管理任务。但是,在您创建封装非托管资源的对象时,当您在应用程序中使用完这些非托管资源之后,您必须显式地释放它们。最常见的一类非托管资源就是包装操作系统资源的对象,例如文件、窗口或网络连接。虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。对于这些类型的对象,.NET Framework 提供 Object.Finalize 方法,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。默认情况下,Finalize 方法不执行任何操作。如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写 Finalize 方法。当使用 C# 和 C++ 的托管扩展以外的编程语言进行开发时,您可以实现 Finalize 方法。C# 和托管扩展提供析构函数作为编写终止代码的简化机制。析构函数自动生成 Finalize 方法和对基类的 Finalize 方法的调用。在 C# 和托管扩展编程语言中,您必须为终止代码使用析构函数语法。
垃圾回收器使用名为“终止队列”的内部结构跟踪具有 Finalize 方法的对象。每次您的应用程序创建具有 Finalize 方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。
实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。
3、清理非托管资源
通过将对象的范围限制为 protected,您可以防止应用程序的用户直接调用对象的 Finalize 方法。除此之外,我们强烈建议您不要直接从应用程序代码中调用非基类的类的 Finalize 方法。为适当处置非托管资源,建议您实现公共的 Dispose 或 Close 方法,这两个方法执行必要的对象清理代码。IDisposable 接口为实现接口的资源类提供 Dispose 方法。因为 Dispose 方法是公共的,所以应用程序的用户可以直接调用该方法来释放非托管资源占用的内存。如果正确实现了 Dispose 方法,则 Finalize 方法(或者 C# 中的析构函数或 C++ 的托管扩展)就成为避免在没有调用 Dispose 方法的情况下清理资源的一种防护措施。有关正确实现的更多信息,请参见实现 Dispose 方法。
(1)实现dispose方法
类型的 Dispose 方法应该释放它拥有的所有资源。它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源。该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用其父类型的 Dispose 方法,从而在整个基类型层次结构中传播该模式。要确保始终正确地清理资源,Dispose 方法应该可以被多次调用而不引发任何异常。
Dispose 方法应该为它处置的对象调用 GC.SuppressFinalize 方法。如果对象当前在终止队列中,GC.SuppressFinalize 防止其 Finalize 方法被调用。请记住,执行 Finalize 方法会大大减损性能。如果您的 Dispose 方法已经完成了清理对象的工作,那么垃圾回收器就不必调用对象的 Finalize 方法了。
下面的代码示例旨在阐释如何为封装了非托管资源的类实现 Dispose 方法的一种可能的设计模式。因为该模式是在整个 .NET Framework 中实现的,所以您可能会发现它十分便于使用。但是,这不是 Dispose 方法唯一可能的实现。
资源类通常是从复杂的本机类或 API 派生的,而且必须进行相应的自定义。使用这一代码模式作为创建资源类的一个起始点,并根据封装的资源提供必要的自定义。不能编译该示例,也不能将其直接用于应用程序。
在此示例中,基类 BaseResource 实现可由类的用户调用的公共 Dispose 方法。而该方法又调用 virtual Dispose(bool disposing) 方法(Visual Basic 中为 virtual Dispose(disposing As Boolean))。根据调用方的标识传递“真”或“假”。以虚 Dispose 方法为对象执行适当的清理代码。
Dispose(bool disposing) 以两种截然不同的方案执行。如果“处置”等于“真”,则该方法已由用户的代码直接调用或间接调用,并且可处置托管资源和非托管资源。如果“处置”等于“假”,则该方法已由运行库从终结器内部调用,并且只能处置非托管资源。因为终结器不会以任意特定的顺序执行,所以当对象正在执行其终止代码时,不应引用其他对象。如果正在执行的终结器引用了另一个已经终止的对象,则该正在执行的终结器将失败。
基类提供的 Finalize 方法或析构函数在未能调用 Dispose 的情况下充当防护措施。Finalize 方法调用带有参数的 Dispose 方法,同时传递“假”。不应在 Finalize 方法内重新创建 Dispose 清理代码。调用 Dispose(false) 可以优化代码的可读性和可维护性。
类 MyResourceWrapper 阐释如何使用 Dispose 从实现资源管理的类派生。MyResourceWrapper 重写 virtual Dispose(bool disposing) 方法并为其创建的托管和非托管资源提供清理代码。MyResourceWrapper 还对其基类 BaseResource 调用 Dispose 以确保其基类能够适当地进行清理。请注意,派生类 MyResourceWrapper 没有不带参数的 Finalize 方法或 Dispose 方法,因为这两个方法从基类 BaseResource 继承它们。
注意 此示例中的 protected Dispose(bool disposing) 方法不强制线程安全,因为无法从用户线程和终结器线程同时调用该方法。另外,使用 BaseResource 的客户端应用程序应从不允许多个用户线程同时调用 protected Dispose(bool disposing) 方法。应用程序或类库的设计原则为:应用程序或类库应只允许一个线程拥有资源的生存期,以及在不再需要资源时调用 Dispose。根据资源的不同,在处置资源时进行异步线程访问可能会带来安全风险。开发人员应仔细检查自己的代码,以确定最佳的方法来强制线程安全。
[Visual Basic]
' Design pattern for the base class.
' By implementing IDisposable, you are announcing that instances
' of this type allocate scarce resources.
Public Class BaseResource
Implements IDisposable
' Pointer to an external unmanaged resource.
Private handle As IntPtr
' Other managed resource this class uses.
Private Components As Component
' Track whether Dispose has been called.
Private disposed As Boolean = False
' Constructor for the BaseResource Object.
Public Sub New()
' Insert appropriate constructor code here.
End Sub
' Implement IDisposable.
' Do not make this method Overridable.
' A derived class should not be able to override this method.
Public Overloads Sub Dispose()Implements IDisposable.Dispose
Dispose(true)
' Take yourself off of the finalization queue
' to prevent finalization code for this object
' from executing a second time.
GC.SuppressFinalize(Me)
End Sub
' Dispose(disposing As Boolean) executes in two distinct scenarios.
' If disposing is true, the method has been called directly
' or indirectly by a user's code. Managed and unmanaged resources
' can be disposed.
' If disposing equals false, the method has been called by the runtime
' from inside the finalizer and you should not reference other
' objects. Only unmanaged resources can be disposed.
Protected Overloads Overridable Sub Dispose(disposing As Boolean)
' Check to see if Dispose has already been called.
If Not (Me.disposed) Then
' If disposing equals true, dispose all managed
' and unmanaged resources.
If (disposing) Then
' Dispose managed resources.
Components.Dispose()
End If
' Release unmanaged resources. If disposing is false,
' only the following code is executed.
CloseHandle(handle)
handle = IntPtr.Zero
' Note that this is not thread safe.
' Another thread could start disposing the object
' after the managed resources are disposed,
' but before the disposed flag is set to true.
' If thread safety is necessary, it must be
' implemented by the client.
End If
Me.disposed = true
End Sub
' This Finalize method will run only if the
' Dispose method does not get called.
' By default, methods are NotOverridable.
' This prevents a derived class from overriding this method.
Protected Overrides Sub Finalize()
' Do not re-create Dispose clean-up code here.
' Calling Dispose(false) is optimal in terms of
' readability and maintainability.
Dispose(false)
End Sub
' Allow your Dispose method to be called multiple times,
' but throw an exception if the object has been disposed.
' Whenever you do something with this class,
' check to see if it has been disposed.
Public Sub DoSomething()
If Me.disposed Then
Throw New ObjectDisposedException()
End if
End Sub
End Class
' Design pattern for a derived class.
' Note that this derived class inherently implements the
' IDisposable interface because it is implemented in the base class.
Public Class MyResourceWrapper
Inherits BaseResource
' A managed resource that you add in this derived class.
private addedManaged As ManagedResource
' A native unmanaged resource that you add in this derived class.
private addedNative As NativeResource
' Track whether Dispose has been called.
Private disposed As Boolean = False
' Constructor for the MyResourceWrapper object.
Public Sub New()
MyBase.New()
' Insert appropriate constructor code here for the
' added resources.
End Sub
Protected Overloads Overrides Sub Dispose(disposing As Boolean)
If Not (Me.disposed) Then
Try
If disposing Then
' Release the managed resources you added in
' this derived class here.
addedManaged.Dispose()
End If
' Release the native unmanaged resources you added
' in this derived class here.
CloseHandle(addedNative)
Me.disposed = true
Finally
' Call Dispose on your base class.
MyBase.Dispose(disposing)
End Try
End If
End Sub
End Class
' This derived class does not have a Finalize method
' or a Dispose method without parameters because it
' inherits them from the base class.
[C#]
// Design pattern for the base class.
// By implementing IDisposable, you are announcing that instances
// of this type allocate scarce resources.
public class BaseResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component Components;
// Track whether Dispose has been called.
private bool disposed = false;
// Constructor for the BaseResource object.
public BaseResource()
{
// Insert appropriate constructor code here.
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// Take yourself off the Finalization queue
// to prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
Components.Dispose();
}
// Release unmanaged resources. If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note that this is not thread safe.
// Another thread could start disposing the object
// after the managed resources are disposed,
// but before the disposed flag is set to true.
// If thread safety is necessary, it must be
// implemented by the client.
}
disposed = true;
}
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~BaseResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
// Allow your Dispose method to be called multiple times,
// but throw an exception if the object has been disposed.
// Whenever you do something with this class,
// check to see if it has been disposed.
public void DoSomething()
{
if(this.disposed)
{
throw new ObjectDisposedException();
}
}
}
// Design pattern for a derived class.
// Note that this derived class inherently implements the
// IDisposable interface because it is implemented in the base class.
public class MyResourceWrapper: BaseResource
{
// A managed resource that you add in this derived class.
private ManagedResource addedManaged;
// A native unmanaged resource that you add in this derived class.
private NativeResource addedNative;
private bool disposed = false;
// Constructor for this object.
public MyResourceWrapper()
{
// Insert appropriate constructor code here.
}
protected override void Dispose(bool disposing)
{
if(!this.disposed)
{
try
{
if(disposing)
{
// Release the managed resources you added in
// this derived class here.
addedManaged.Dispose();
}
// Release the native unmanaged resources you added
// in this derived class here.
CloseHandle(addedNative);
this.disposed = true;
}
finally
{
// Call Dispose on your base class.
base.Dispose(disposing);
}
}
}
}
// This derived class does not have a Finalize method
// or a Dispose method without parameters because it inherits
// them from the base class.
实现 Close 方法
对于类型来说,若调用 Close 方法比调用 Dispose 方法更简易,则可以向基类型添加一个公共 Close 方法。Close 方法又调用没有参数的 Dispose 方法,该方法可以执行正确的清理操作。下面的代码示例阐释了 Close 方法。
[Visual Basic]
' Do not make this method Overridable.
' A derived class should not be allowed
' to override this method.
Public Sub Close()
' Calls the Dispose method without parameters.
Dispose()
End Sub
[C#]
// Do not make this method virtual.
// A derived class should not be allowed
// to override this method.
public void Close()
{
// Calls the Dispose method without parameters.
Dispose();
}
(2)重写finalize方法
Finalize 方法在未能调用 Dispose 方法的情况下充当防护措施来清理资源。您应该只实现 Finalize 方法来清理非托管资源。您不应该对托管对象实现 Finalize 方法,因为垃圾回收器会自动清理托管资源。默认情况下,Object.Finalize 方法不进行任何操作。如果要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写此方法。
注意 您无法使用 C# 或 C++ 编程语言的托管扩展来重写 Finalize 方法。您必须使用这些语言提供的析构函数语法作为编写终止代码的机制。
Object.Finalize 方法的范围是受保护的。当在类中重写该方法时,您应该保持这个有限的范围。通过保护 Finalize 方法,您可以防止应用程序的用户直接调用对象的 Finalize 方法。
对象的 Finalize 方法应该释放该对象保留的所有资源。它还应该调用该对象基类的 Finalize 方法。对象的 Finalize 方法不应对任何非其基类的对象调用方法。这是因为被调用的其他对象可能和调用对象在同一时间被回收,例如公共语言运行库关闭这种情况。
如果您允许任何异常避开 Finalize 方法,系统将认为方法返回,并继续调用其他对象的 Finalize 方法。
(3)使用 C# 和 C++ 托管扩展的析构函数语法
您无法从 C# 或 C++ 编程语言的托管扩展中调用或重写 Object.Finalize 方法。C# 和托管扩展提供析构函数作为编写终止代码的机制。在 C# 和托管扩展中,您必须使用析构函数语法来执行清理操作。因为该语法隐式地为对象基类调用 Finalize 方法,所以十分方便易用。这保证了对当前类从其导出的所有级别的析构函数都调用了 Finalize。
下面的代码示例是为析构函数编写的。
~MyClass()
{
// Perform some cleanup operations here.
}
该代码隐式翻译为下面的代码。
protected override void Finalize()
{
try
{
// Perform some cleanup operations here.
}
finally
{
base.Finalize();
}
}
注意 虽然它们看上去相似,但 C# 和托管扩展析构函数与非托管 C++ 析构函数具有不同的语义。托管代码不支持任何与 C++ 析构函数语义相似的语义。
4、强制垃圾回收
介绍如何以及何时强制垃圾回收器执行回收。
垃圾回收 GC 类提供 GC.Collect 方法,您可以使用该方法让应用程序在一定程度上直接控制垃圾回收器。通常情况下,您应该避免调用任何回收方法,让垃圾回收器独立运行。在大多数情况下,垃圾回收器在确定执行回收的最佳时机方面更有优势。但是,在某些不常发生的情况下,强制回收可以提高应用程序的性能。当应用程序代码中某个确定的点上使用的内存量大量减少时,在这种情况下使用 GC.Collect 方法可能比较合适。例如,应用程序可能使用引用大量非托管资源的文档。当您的应用程序关闭该文档时,您完全知道已经不再需要文档曾使用的资源了。出于性能的原因,一次全部释放这些资源很有意义。有关更多信息,请参见 GC.Collect 方法。
在垃圾回收器执行回收之前,它会挂起当前正在执行的所有线程。如果不必要地多次调用 GC.Collect,这可能会造成性能问题。您还应该注意不要将调用 GC.Collect 的代码放置在程序中用户可以经常调用的点上。这可能会削弱垃圾回收器中优化引擎的作用,而垃圾回收器可以确定运行垃圾回收的最佳时间。
5、相关简介
(1)GC类
控制系统垃圾回收器(一种自动回收未使用内存的服务)。
有关此类型所有成员的列表,请参阅 GC 成员。
System.Object
System.GC
[Visual Basic]
NotInheritable Public Class GC
[C#]
public sealed class GC
[C++]
public __gc __sealed class GC
[JScript]
public class GC
线程安全
此类型的所有公共静态(Visual Basic 中为 Shared)成员是线程安全的。但不保证任何实例成员是线程安全的。
备注
此类中的方法影响何时对对象进行垃圾回收以及何时释放对象所分配的资源。此类中的属性提供以下信息:系统可用内存总量、分配给对象的内存的周期类别(代)。
垃圾回收器跟踪并回收托管内存中分配的对象。垃圾回收器定期执行垃圾回收以回收分配给没有有效引用的对象的内存。当使用可用内存不能满足内存请求时,垃圾回收会自动进行。或者,应用程序可以使用 Collect 方法强制进行垃圾回收。
垃圾回收由以下步骤组成:
垃圾回收器搜索托管代码中引用的托管对象。
垃圾回收器尝试完成没有被引用的对象。
垃圾回收器释放没有被引用的对象并回收它们的内存。
在回收期间,如果垃圾回收器在托管代码中找到对某对象的一个或多个引用,则不会释放该对象。然而,垃圾回收器不识别非托管代码中对对象的引用,因此,除非明确禁止,否则它有可能释放非托管代码中以独占方式使用的对象。KeepAlive 方法提供一种机制,该机制可防止垃圾回收器回收在非托管代码中仍使用的对象。
除托管内存分配外,垃圾回收器的实现不维护对象所保持的资源(如文件句柄或数据库连接)的信息。当某个类型使用的非托管资源在回收该类型的实例之前必须释放时,该类型可以实现完成器。
多数情况下,完成器通过重写 Object.Finalize 方法来实现,但是,用 C# 或 C++ 编写的类型实现析构函数,由编译器将析构函数转换为对 Object.Finalize 的重写。多数情况下,如果某对象有完成器,则垃圾回收器会在释放该对象前调用其完成器。然而,并不是所有情况下都需要垃圾回收器调用完成器。此外,不需要垃圾回收器使用特定线程来完成对象,也不需要垃圾回收器为相互引用、但能以其他方式用于垃圾回收的对象保证完成器的调用顺序。
在资源必须在特定时间释放的方案中,类可以实现 IDisposable 接口,该接口包含执行资源管理和清理任务的 IDisposable.Dispose 方法。实现 Dispose 的类作为它们的类协定的一部分,必须指定类使用者是否需要及在什么时候调用该方法来清理对象。默认情况下,垃圾回收器并不调用 Dispose 方法,然而 Dispose 方法的实现可以调用 GC 类中的方法来自定义垃圾回收器的完成行为。
建议垃圾回收器使用代来支持对象老化,但这不是必需的。代是对象在内存中相对存现时期的度量单位。对象的代数或存现时期说明对象所属的代。较近创建的对象属于较新的代,比在应用程序生命周期中较早创建的对象的代数低。最近代中的对象位于零代中。
对实施者的说明: 垃圾回收器的此实现支持三代。
使用 MaxGeneration 确定系统所支持的最大代数。对象老化允许应用程序针对一组特定的代进行垃圾回收,而不需要垃圾回收器计算所有代。
示例
[Visual Basic]
Imports System
Namespace GCCollectInt_Example
Class MyGCCollectClass
Private maxGarbage As Long = 10000
Public Shared Sub Main()
Dim myGCCol As New MyGCCollectClass
'Determine the maximum number of generations the system
'garbage collector currently supports.
Console.WriteLine("The highest generation is {0}", GC.MaxGeneration)
myGCCol.MakeSomeGarbage()
'Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol))
'Determine the best available approximation of the number
'of bytes currently allocated in managed memory.
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(False))
'Perform a collection of generation 0 only.
GC.Collect(0)
'Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol))
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(False))
'Perform a collection of generation 2 only.
GC.Collect(2)
'Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol))
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(False))
Console.Read()
End Sub
Sub MakeSomeGarbage()
Dim vt As Version
Dim i As Integer
For i = 0 To maxGarbage - 1
'Create objects and release them to fill up memory
'with unused objects.
vt = New Version
Next i
End Sub
End Class
End Namespace
[C#]
using System;
namespace GCCollectIntExample
{
class MyGCCollectClass
{
private const long maxGarbage = 1000;
static void Main()
{
MyGCCollectClass myGCCol = new MyGCCollectClass();
// Determine the maximum number of generations the system
// garbage collector currently supports.
Console.WriteLine("The highest generation is {0}", GC.MaxGeneration);
myGCCol.MakeSomeGarbage();
// Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));
// Determine the best available approximation of the number
// of bytes currently allocated in managed memory.
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
// Perform a collection of generation 0 only.
GC.Collect(0);
// Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
// Perform a collection of generation 2 only.
GC.Collect(2);
// Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));
Console.Read();
}
void MakeSomeGarbage()
{
Version vt;
for(int i = 0; i < maxGarbage; i++)
{
// Create objects and release them to fill up memory
// with unused objects.
vt = new Version();
}
}
}
}
[C++]
#using <mscorlib.dll>
using namespace System;
const long maxGarbage = 1000;
__gc class MyGCCollectClass {
public:
void MakeSomeGarbage() {
Version* vt;
for (int i = 0; i < maxGarbage; i++) {
// Create objects and release them to fill up memory
// with unused objects.
vt = new Version();
}
}
};
int main() {
MyGCCollectClass* myGCCol = new MyGCCollectClass();
// Determine the maximum number of generations the system
// garbage collector currently supports.
Console::WriteLine(S"The highest generation is {0}", __box(GC::MaxGeneration));
myGCCol->MakeSomeGarbage();
// Determine which generation myGCCol object is stored in.
Console::WriteLine(S"Generation: {0}", __box(GC::GetGeneration(myGCCol)));
// Determine the best available approximation of the number
// of bytes currently allocated in managed memory.
Console::WriteLine(S"Total Memory: {0}", __box(GC::GetTotalMemory(false)));
// Perform a collection of generation 0 only.
GC::Collect(0);
// Determine which generation myGCCol object is stored in.
Console::WriteLine(S"Generation: {0}", __box(GC::GetGeneration(myGCCol)));
Console::WriteLine(S"Total Memory: {0}", __box(GC::GetTotalMemory(false)));
// Perform a collection of generation 2 only.
GC::Collect(2);
// Determine which generation myGCCol object is stored in.
Console::WriteLine(S"Generation: {0}", __box(GC::GetGeneration(myGCCol)));
Console::WriteLine(S"Total Memory: {0}", __box(GC::GetTotalMemory(false)));
}
[JScript] 没有可用于 JScript 的示例。若要查看 Visual Basic、C# 或 C++ 示例,请单击页左上角的“语言筛选器”按钮 。
要求
命名空间: System
平台: Windows 98, Windows NT 4.0, Windows ME, Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003 系列, .NET Framework 精简版
程序集: Mscorlib (在 Mscorlib.dll 中)
(2)Object.Finalize 方法
允许 Object 在“垃圾回收”回收 Object 之前尝试释放资源并执行其他清理操作。
[C#] 在 C# 中,使用析构函数语法表示终止程序。
[C++] 在 C++ 中,使用析构函数语法表示终止程序。
[Visual Basic]
Overrides Protected Sub Finalize()
[C#]
~Object();
[C++]
~Object();
[JScript]
protected override function Finalize();
备注
Finalize 是受保护的,因此只能通过此类或派生类访问它。
对象变为不可访问后将自动调用此方法,除非已通过 SuppressFinalize 调用使对象免除了终结。在应用程序域的关闭过程中,对没有免除终结的对象将自动调用 Finalize,即使那些对象仍是可访问的。对于给定的实例仅自动调用 Finalize 一次,除非使用 ReRegisterForFinalize 这类机制重新注册该对象并且后面没有调用 GC.SuppressFinalize。
派生类型中的每个 Finalize 实现都必须调用其基类型的 Finalize 实现。这是唯一一种允许应用程序代码调用 Finalize 的情况。
Finalize 操作具有下列限制:
垃圾回收过程中执行终结程序的准确时间是不确定的。不保证资源在任何特定的时间都能释放,除非调用 Close 方法或 Dispose 方法。
即使一个对象引用另一个对象,也不能保证两个对象的终结程序以任何特定的顺序运行。即,如果对象 A 具有对对象 B 的引用,并且两者都有终结程序,则当对象 A 的终结程序启动时,对象 B 可能已经终结了。
运行终结程序的线程是未指定的。
在下面的异常情况下,Finalize 方法可能不会运行完成或可能根本不运行:
另一个终结程序无限期地阻塞(进入无限循环,试图获取永远无法获取的锁,诸如此类)。由于运行时试图运行终结程序来完成,所以如果一个终结程序无限期地阻塞,则可能不会调用其他终结程序。
进程终止,但不给运行时提供清理的机会。在这种情况下,运行时的第一个进程终止通知是 DLL_PROCESS_DETACH 通知。
在关闭过程中,只有当可终结对象的数目继续减少时,运行时才继续 Finalize 对象。
如果 Finalize 或 Finalize 的重写引发异常,运行时将忽略异常、终止此 Finalize 方法,并继续终结进程。
对实施者的说明:
默认情况下,Object.Finalize 不执行任何操作。只有在必要时才必须由派生类重写它,因为如果必须运行 Finalize 操作,垃圾回收过程中的回收往往需要长得多的时间。
如果 Object 保存了对任何资源的引用,则 Finalize 必须由派生类重写,以便在垃圾回收过程中,在放弃 Object 之前释放这些资源。
当类型使用文件句柄或数据库连接这类在回收使用托管对象时必须释放的非托管资源时,该类型必须实现 Finalize。有关辅助和具有更多控制的资源处置方式,请参见 IDisposable 接口。
Finalize 可以采取任何操作,包括在垃圾回收过程中清理了对象后使对象复活(即,使对象再次可访问)。但是,对象只能复活一次;在垃圾回收过程中,不能对复活对象调用 Finalize。
[C#] 析构函数是执行清理操作的 C# 机制。析构函数提供了适当的保护措施,如自动调用基类型的析构函数。在 C# 代码中,不能调用或重写 Object.Finalize。
要求
平台: Windows 98, Windows NT 4.0, Windows ME, Windows 2000, Windows XP Home Edition, Windows XP Professional, Windows Server 2003 系列, .NET Framework 精简版, 公共语言基础结构 (CLI) 标准
(3)IDisposable 接口
定义一种释放分配的非托管资源的方法。
有关此类型所有成员的列表,请参阅 IDisposable 成员。
[Visual Basic]
Public Interface IDisposable
[C#]
public interface IDisposable
[C++]
public __gc __interface IDisposable
[JScript]
public interface IDisposable
实现 IDisposable 的类
类 说明
AsymmetricAlgorithm 表示所有不对称算法的实现都必须从中继承的抽象基类。
BinaryReader 用特定的编码将基元数据类型读作二进制值。
BinaryWriter 以二进制形式将基元类型写入流,并支持用特定的编码写入字符串。
Brush 从此抽象基类派生出的类定义用于填充图形形状(如矩形、椭圆形、扇形、多边形和封闭路径)内部的对象。
CacheDependency 跟踪缓存依赖项,缓存依赖项可以是应用程序的 Cache 中的文件、目录或与其他对象的键。无法继承此类。
Component 提供 IComponent 接口的基实现并启用应用程序之间的对象共享。
ComponentDesigner 用于扩展组件的设计模式行为的基本设计器类。
Container 封装零个或更多个组件。
Control 定义由所有 ASP.NET 服务器控件共享的属性、方法和事件。
CryptoAPITransform 执行数据的加密转换。
Cursor 代表用于绘制鼠标指针的图像。
CustomLineCap 封装自定义的用户定义的线帽。
DesignerTransaction 提供一种方法来对一系列的设计时操作进行分组,从而提高性能并使得大多数类型的更改都能撤消。
EncoderParameter 可以使用 EncoderParameter 对象将值的数组传递给图像编码器。还可以使用 EncoderParameter 对象来接收特定图像编码器的特定参数所支持的一系列可能的值。
EncoderParameters 封装 EncoderParameter 对象的数组。
EventHandlerList 提供一个简单的委托列表。不能继承此类。
Font 定义特定的文本格式,包括字体、字号和字形属性。无法继承此类。
FontCollection 已安装和私有字体集合的基类。提供用于获取集合中所包含字体族的列表的方法。有关字体和文本的附加信息(包括代码示例),请参见这些文档的“使用 GDI+ 托管类”一节中的“字体和文本”。
FontFamily 定义有着相似的基本设计但在形式上有某些差异的一组字样。无法继承此类。
FromBase64Transform 从 Base 64 转换 CryptoStream。
Graphics 封装 GDI+ 绘图面。无法继承此类。
GraphicsPath 表示一系列相互连接的直线和曲线。无法继承此类。
GraphicsPathIterator 提供循环访问 GraphicsPath 对象中的子路径并测试每一子路径中包含的形状类型的能力。无法继承此类。
HashAlgorithm 表示所有加密哈希算法实现均必须从中派生的基类。
HttpApplication 定义 ASP.NET 应用程序中的所有应用程序对象通用的方法、属性和事件。此类是由用户在 global.asax 文件中定义的应用程序的基类。
Icon 表示 Windows 图标,它是用于表示对象的小位图图像。尽管图标的大小由系统决定,但仍可将其视为透明的位图。
Image 为源自 Bitmap 和 Metafile 的类提供功能的抽象基类。
ImageAttributes ImageAttributes 对象包含有关在呈现时如何操作位图和图元文件颜色的信息。ImageAttributes 对象维护多个颜色调整设置,包括颜色调整矩阵、灰度调整矩阵、伽玛校正值、颜色映射表和颜色阈值。
呈现过程中,可以对颜色进行校正、调暗、调亮或删除等等。要应用这些操作,请初始化 ImageAttributes 对象,并将 ImageAttributes 对象的地址(连同 Image 对象的地址)传递给 DrawImage 方法。
IsolatedStorageFile 表示包含文件和目录的独立存储区。
License 为所有许可证提供抽象(在 Visual Basic 中为 MustInherit)基类。向组件的特定实例授予许可证。
LocalizationExtenderProvider 向根设计器提供本地化功能的设计时支持。
ManagementObjectCollection 表示通过 WMI 检索到的管理对象的不同集合。此集合中的对象为从 ManagementBaseObject 派生的类型,包括 ManagementObject 和 ManagementClass。
通过 ManagementObjectSearcher 对象执行 WMI 查询,或者通过表示指定类型的 ManagementClass 检索该类型管理对象的枚举,能够得到此集合。此外,这也可能是以指定方式与特定管理对象相关的管理对象集合 — 在这种情况下,此集合可以通过诸如 GetRelated 之类的方法检索到。
此集合可以通过 ManagementObjectCollection.ManagementObjectEnumerator 遍历,并且能够针对各种管理任务对集合中的对象进行检查或操作。
ManagementObjectCollection.ManagementObjectEnumerator 表示集合的枚举数。
MarshalByValueComponent 实现 IComponent 并提供可远程控制的组件的基实现,该组件是由值封送的(传递序列化对象的副本)。
Matrix 封装表示几何变形的 3 x 3 仿射矩阵。无法继承此类。
MessageEnumerator 提供一个只进游标,用来枚举通过消息队列中的消息。
MessageQueueEnumerator 提供一个只进游标,以枚举通过消息队列中的消息。
MessageQueueTransaction 提供消息队列内部事务。
OdbcDataReader 提供从数据源读取数据行的只进流的方法。无法继承此类。
OdbcTransaction 表示要在数据源执行的 SQL 事务。不能继承此类。
OleDbDataReader 提供从数据源读取数据行的只进流的方法。无法继承此类。
OleDbTransaction 表示要在数据源执行的 SQL 事务。无法继承此类。
OracleDataReader 提供从数据源读取数据行的只进流的方法。无法继承此类。
OracleTransaction 表示要在数据库中生成的事务。无法继承此类。
PaintEventArgs 为 Paint 事件提供数据。
Pen 定义用于绘制直线和曲线的对象。无法继承此类。
Region 指示由矩形和由路径构成的图形形状的内部。无法继承此类。
RegistryKey 表示 Windows 注册表中的项级节点。此类是注册表封装。
ResourceReader 枚举 .resources 文件和流,并读取顺序的资源名和资源值对。
ResourceSet 存储已针对某个特定区域性进行了本地化的所有资源,忽略所有其他区域性(包括任何代用规则)。
ResourceWriter 以系统默认的格式将资源写入输出文件或输出流。
ResXResourceReader 枚举 XML 资源 (.resx) 文件和流,并读取顺序资源名称和值对。
ResXResourceWriter 将资源写入 XML 资源 (.resx) 文件或输出流。
SearchResultCollection 包含在 DirectorySearcher 查询过程中由 Active Directory 层次结构返回的 SearchResult 实例。
ServicedComponent 表示使用 COM+ 服务的所有类的基类。
Socket 实现 Berkeley 套接字接口。
SqlCeCommand 表示对数据源执行的 SQL 语句。
SqlCeConnection 表示到数据源的连接是打开的。
SqlCeDataReader 提供从数据源读取数据行的只进流的方法。无法继承此类。
SqlCeEngine 表示 SQL Server CE 引擎的属性、方法及其他对象。不能继承此类。
SqlCeRemoteDataAccess 初始化 SqlCeRemoteDataAccess 对象的新实例。有关“远程数据访问”的更多信息,请参见“SQL Server CE 联机图书”。
SqlCeReplication 初始化 SqlCeReplication 对象的新实例。有关复制的更多信息,请参见“SQL Server 联机图书”。有关 SQL Server CE 中合并复制的更多信息,请参见“SQL Server CE 联机图书”。
SqlCeTransaction 表示要在数据源执行的 SQL 事务。不能继承此类。
SqlDataReader 提供一种从数据库读取只进的行流的一种方式。无法继承此类。
SqlTransaction 表示要在 SQL Server 数据库中处理的 Transact-SQL 事务。无法继承此类。
Stream 提供字节序列的一般视图。
StringFormat 封装文本布局信息(如对齐方式和行距),显示操作(如省略号插入和国家标准 (National) 数字位替换)和 OpenType 功能。无法继承此类。
SymmetricAlgorithm 表示所有对称算法的实现都必须从中继承的抽象基类。
TcpClient 为 TCP 网络服务提供客户端连接。
TempFileCollection 表示临时文件的集合。
TemplateEditingVerb 表示一个设计器谓词,该谓词创建模板编辑框并且只能由模板编辑器调用。
TextReader 表示可读取连续字符系列的阅读器。
TextWriter 表示可以编写一个有序字符系列的编写器。该类为抽象类。
Timer 提供以指定的时间间隔执行方法的机制。无法继承此类。
ToBase64Transform 将 CryptoStream 转换为 Base 64。
TraceListener 为监视跟踪和调试输出的侦听器提供抽象(在 Visual Basic 中为 MustInherit)基类。
UdpClient 提供用户数据文报 (UDP) 网络服务。
WaitHandle 封装等待对共享资源的独占访问权的操作系统特定的对象。
WebResponse 提供来自统一资源标识符 (URI) 的响应。这是一个抽象(在 Visual Basic 中为 MustInherit)类。
备注
当托管对象不再使用时,垃圾回收器会自动释放分配给该对象的内存,不过,进行垃圾回收的时间不可预知。另外,垃圾回收器对窗口句柄、打开的文件和流等非托管资源一无所知。
将此接口的 Dispose 方法与垃圾回收器一起使用来显式释放非托管资源。当不再需要对象时,对象的使用者可以调用此方法。
向现有类添加 IDisposable 接口是重大的更改,因为它更改了类的语义。
有关如何使用此接口和 Object.Finalize 方法的详细讨论,请参见垃圾回收编程和实现 Dispose 方法主题。
示例
[Visual Basic]
Imports System
Imports System.ComponentModel
' The following example demonstrates how to create
' a resource class that implements the IDisposable interface
' and the IDisposable.Dispose method.
Public Class DisposeExample
' A class that implements IDisposable.
' By implementing IDisposable, you are announcing that
' instances of this type allocate scarce resources.
Public Class MyResource
Implements IDisposable
' Pointer to an external unmanaged resource.
Private handle As IntPtr
' Other managed resource this class uses.
Private component As component
' Track whether Dispose has been called.
Private disposed As Boolean = False
' The class constructor.
Public Sub New(ByVal handle As IntPtr)
Me.handle = handle
End Sub
' Implement IDisposable.
' Do not make this method virtual.
' A derived class should not be able to override this method.
Public Overloads Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
' This object will be cleaned up by the Dispose method.
' Therefore, you should call GC.SupressFinalize to
' take this object off the finalization queue
' and prevent finalization code for this object
' from executing a second time.
GC.SuppressFinalize(Me)
End Sub
' Dispose(bool disposing) executes in two distinct scenarios.
' If disposing equals true, the method has been called directly
' or indirectly by a user's code. Managed and unmanaged resources
' can be disposed.
' If disposing equals false, the method has been called by the
' runtime from inside the finalizer and you should not reference
' other objects. Only unmanaged resources can be disposed.
Private Overloads Sub Dispose(ByVal disposing As Boolean)
' Check to see if Dispose has already been called.
If Not Me.disposed Then
' If disposing equals true, dispose all managed
' and unmanaged resources.
If disposing Then
' Dispose managed resources.
component.Dispose()
End If
' Call the appropriate methods to clean up
' unmanaged resources here.
' If disposing is false,
' only the following code is executed.
CloseHandle(handle)
handle = IntPtr.Zero
End If
disposed = True
End Sub
' Use interop to call the method necessary
' to clean up the unmanaged resource.
<System.Runtime.InteropServices.DllImport("Kernel32")> _
Private Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]
End Function
' This finalizer will run only if the Dispose method
' does not get called.
' It gives your base class the opportunity to finalize.
' Do not provide finalize methods in types derived from this class.
Protected Overrides Sub Finalize()
' Do not re-create Dispose clean-up code here.
' Calling Dispose(false) is optimal in terms of
' readability and maintainability.
Dispose(False)
MyBase.Finalize()
End Sub
End Class
Public Shared Sub Main()
' Insert code here to create
' and use the MyResource object.
End Sub
End Class
[C#]
using System;
using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
public class DisposeExample
{
// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)