NET Framework 垃圾回收 35 Version.docx

上传人:b****5 文档编号:6208466 上传时间:2023-01-04 格式:DOCX 页数:22 大小:501.84KB
下载 相关 举报
NET Framework 垃圾回收 35 Version.docx_第1页
第1页 / 共22页
NET Framework 垃圾回收 35 Version.docx_第2页
第2页 / 共22页
NET Framework 垃圾回收 35 Version.docx_第3页
第3页 / 共22页
NET Framework 垃圾回收 35 Version.docx_第4页
第4页 / 共22页
NET Framework 垃圾回收 35 Version.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

NET Framework 垃圾回收 35 Version.docx

《NET Framework 垃圾回收 35 Version.docx》由会员分享,可在线阅读,更多相关《NET Framework 垃圾回收 35 Version.docx(22页珍藏版)》请在冰豆网上搜索。

NET Framework 垃圾回收 35 Version.docx

NETFramework垃圾回收35Version

垃圾回收

Framework3.5version

Author:

JerryHuang

目录

1.垃圾回收概述

2.Finalize方法和析构函数

3.弱引用

4.被动回收

5.滞后时间模式

6.针对共享WEB宿主优化

7.垃圾回收通知

8.清理非托管资源

9.参考C#析构函数

10.参考WeakReference类

11.参考垃圾回收内部原理

 

垃圾回收

.NETFramework的垃圾回收器管理应用程序的内存分配和释放。

每次您使用new运算符创建对象时,运行时都从托管堆为该对象分配内存。

只要托管堆中有地址空间可用,运行时就会继续为新对象分配空间。

但是,内存不是无限大的。

最终,垃圾回收器必须执行回收以释放一些内存。

垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。

当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存。

本节介绍了垃圾回收器如何自动管理应用程序中托管对象的内存分配和释放。

除此之外,本节还介绍了推荐的设计模式,以用来正确地清理应用程序创建的任何非托管资源。

说明:

在.NETFramework1.0版中,公共语言运行时(CLR)具有一个用于大型对象堆的独立内存管理器。

在某些情况下,该内存管理器不将未使用的内存返回给操作系统,在少数情况下,它还会使该内存不能垃圾回收。

这样会由于虚拟地址空间碎片而导致内存分配失败。

在.NETFramework1.1和2.0版中,大型对象堆由称为堆片段的连续内存区域组成,这些区域完全对齐以使虚拟内存碎片减到最少。

在垃圾回收过程中,从大型对象中回收的空间被合并起来并置于自由列表中。

只包含自由列表项的堆片段被释放,内存被返回给操作系统。

对大型对象堆所做的这些更改有效消除了由这种形式的虚拟地址空间碎片导致的内存分配故障。

重要说明:

在内存大于2GB的服务器中,可能需要在boot.ini文件中指定/3GB开关,以避免当内存仍可供系统使用时出现明显的内存不足问题。

 

本节内容

Finalize方法和析构函数

介绍Finalize方法和析构函数如何允许对象在垃圾回收器自动回收对象的内存之前执行必要的清理操作。

弱引用

介绍允许应用程序访问对象,同时也允许垃圾回收器收集该对象的功能。

被动回收

介绍如何立即或在下一最佳时间回收对象。

滞后时间模式

介绍可确定垃圾回收侵入性的模式。

针对共享Web宿主优化

介绍在通过承载若干个小型网站共享的服务器上如何优化垃圾回收。

垃圾回收通知

介绍如何确定完整垃圾回收何时即将发生以及何时完成。

清理非托管资源

介绍推荐的清理非托管资源的设计模式。

 

Finalize方法和析构函数

对于您的应用程序创建的大多数对象,可以依靠.NETFramework的垃圾回收器隐式地执行所有必要的内存管理任务。

但是,在您创建封装非托管资源的对象时,当您在应用程序中使用完这些非托管资源之后,您必须显式地释放它们。

最常见的一类非托管资源就是包装操作系统资源的对象,例如文件、窗口或网络连接。

虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。

对于这些类型的对象,.NETFramework提供Object.Finalize方法,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。

默认情况下,Finalize方法不执行任何操作。

如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写Finalize方法。

说明:

若要在C#中实现Finalize方法,您必须使用析构函数语法。

在.NETFramework2.0版中,VisualC++为实现Finalize方法提供了自己的语法,详见DestructorsandFinalizersinVisualC++中的介绍。

在.NETFramework1.0版和1.1版中,VisualC++与C#一样,也对Finalize方法使用析构函数语法。

垃圾回收器使用名为“终止队列”的内部结构跟踪具有Finalize方法的对象。

每次您的应用程序创建具有Finalize方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。

托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。

说明:

为GC.KeepAlive方法提供的代码示例演示攻击性垃圾回收如何会导致终结器在已回收的对象的成员仍在执行时运行,以及如何使用KeepAlive方法来阻止这种情况的发生。

Finalize方法不应引发异常,因为应用程序无法处理这些异常,而且这些异常会导致应用程序终止。

实现Finalize方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。

用Finalize方法回收对象使用的内存需要至少两次垃圾回收。

当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。

这时,它不能回收具有终结器的不可访问对象。

它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。

该列表中的项指向托管堆中准备被调用其终止代码的对象。

垃圾回收器为此列表中的对象调用Finalize方法,然后,将这些项从列表中移除。

后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。

在后来的垃圾回收中,实际上回收了对象的内存。

示例:

对象A:

没有终结器(Finalize)的不可访问对象。

对象B:

有终结器(Finalize)的不可访问对象。

弱引用

如果应用程序的代码可以访问一个正由该程序使用的对象,垃圾回收器就不能收集该对象,那么,就认为应用程序对该对象具有强引用。

弱引用允许应用程序访问对象,同时也允许垃圾回收器收集相应的对象。

如果不存在强引用,则弱引用的有限期只限于收集对象前的一个不确定的时间段。

使用弱引用时,应用程序仍可对该对象进行强引用,这样做可防止该对象被收集。

但始终存在这样的风险:

垃圾回收器在重新建立强引用之前先处理该对象。

弱引用特别适合以下对象:

占用大量内存,但通过垃圾回收功能回收以后很容易重新创建。

假设Windows窗体应用程序中的一个树视图向用户显示了复杂的选项层次结构。

如果基础数据量很大,则用户使用应用程序中的其他部分时,在内存中保留该树会导致效率低下。

当用户切换到应用程序的其他部分时,可使用WeakReference类来创建对该树的弱引用,并销毁所有强引用。

当用户切换回该树时,应用程序会尝试获得对该树的强引用,如果得到,就不必重新构造该树。

要对某个对象建立弱引用,请使用要跟踪的对象的实例创建一个WeakReference。

然后将Target属性设置为该对象,将该对象设置为null。

有关代码示例,请参见类库中的WeakReference。

短弱引用和长弱引用

可创建短弱引用或长弱引用:

垃圾回收功能回收对象后,短弱引用的目标会变为null。

弱引用本身是托管对象,和任何其他托管对象一样需要经过垃圾回收。

短弱引用是WeakReference的默认构造函数。

调用对象的Finalize方法后,会保留长弱引用。

这样,您就可以重新创建该对象,但该对象仍保持不可预知的状态。

要使用长引用,请在WeakReference构造函数中指定true。

如果对象的类型没有Finalize方法,则会应用短弱引用功能,该弱引用只在目标被收集之前有效,运行终结器之后可以随时收集目标。

要建立强引用并重新使用该对象,请将WeakReference的Target属性强制转换为该对象的类型。

如果Target属性返回null,则表示对象已被收集;否则,您可继续使用该对象,因为应用程序已重新获得了对它的强引用。

使用弱引用的准则

仅在必要时使用长弱引用,因为在终止后对象的状态是不可预知的。

避免对小对象使用弱引用,因为指针本身可能和对象一样大,或者比对象还大。

不应将弱引用作为内存管理问题的自动解决方案,而应开发一个有效的缓存策略来处理应用程序的对象。

 

被动回收

在大多数情况下,垃圾回收器可以确定执行回收的最佳时间,应让其独立运行。

在某些不常发生的情况下,强制回收可以提高应用程序的性能。

在这些情况下,可使用Collect方法强制垃圾回收,以引发垃圾回收。

当应用程序代码中某个确定的点上使用的内存量大量减少时,请使用Collect方法。

例如,如果应用程序使用包含若干个控件的复杂对话框,则在对话框关闭时调用Collect可能会通过立即回收内存来提高性能。

务必确保应用程序不会过于频繁地引发垃圾回收,否则当垃圾回收器无效率地尝试回收对象时,可能会使性能降低。

Optimized模式使垃圾回收器可以根据收集是否有效率来确定是否进行回收。

GC回收模式

可以使用GC.Collect方法重载,它使用GCCollectionMode值指定强制回收的行为,如下表所述。

成员

说明

Default

使用指定的设置作为正在运行的.NETFramework版本的默认垃圾回收配置。

Forced

强制立即执行垃圾回收。

这等效于调用GC.Collect()。

Optimized

使垃圾回收器可以确定当前时间是否是回收对象的最佳时间。

垃圾回收器可能判定收集效率不够高,因此收集不合理,在这种情况下将返回而不回收对象。

 

滞后时间模式

若要回收对象,垃圾回收器必须停止应用程序的所有正在执行的线程。

在某些情况下,例如当应用程序检索数据或者显示内容时,完整垃圾回收可能会在关键时刻进行,而且可能会影响性能。

可以通过将LatencyMode属性设置为GCLatencyMode值之一来调整垃圾回收器的侵入性。

滞后时间指的是垃圾回收器侵入应用程序的时间。

在低滞后时间期间,垃圾回收器在回收对象时较保守且侵入性较弱。

第2代回收不常发生,这使得应用程序工作集随着时间而增长。

因此,建议您在需要LowLatency模式时仅在短时间内使用该模式。

否则,如果系统处于内存压力下,垃圾回收器将触发一次回收,这样会暂时暂停应用程序并中断对时间要求很急的操作。

低滞后时间模式应当用于以下应用程序:

包含运行时间较短的代码块,而且必须在运行时中断最少的情况下运行。

虽然LowLatency模式设计用于存在某些时间限制的情况中,但它并不是针对存在严格实时限制的情况的解决方案。

下表列出了GCLatencyMode值适用的应用程序方案。

滞后时间模式

应用程序方案

Batch

适用于没有UI或服务器端操作的应用程序。

 

 

Interactive

适用于多数有UI的应用程序。

 

LowLatency

适用于在垃圾回收器的中断可以中断时具有时效性短期操作的应用程序。

例如,执行动画呈现或数据采集功能的应用程序。

 

默认垃圾回收模式

如果未指定LatencyMode属性,则默认模式为并发工作站垃圾回收。

该模式取决于两个运行时配置设置的值:

如果启用,则此设置指定公共语言运行时在单独的线程上运行工作站垃圾回收以支持并发操作。

默认情况下会启用此设置。

如果启用,则此设置指定公共语言运行时运行服务器垃圾回收;如果未启用,则运行工作站垃圾回收。

只能在具有两个或更多处理器的计算机上启用服务器垃圾回收。

默认情况下不启用此选项。

如果启用此设置,则自动禁用

GCLatencyMode的默认值如下:

在启用且禁用时为Interactive。

在禁用时或同时启用时为Batch。

说明:

如果应用程序在实现IntelItanium体系结构的64位系统(以前称为IA-64)上运行WOW64x86仿真程序,则在这些应用程序中不支持并发垃圾回收。

有关在64位Windows系统上使用WOW64的更多信息,请参见Running32-bitApplications(运行32位应用程序)。

低滞后时间使用准则

使用LowLatency模式时,请考虑下列准则:

使处于低滞后时间模式的时间尽可能短。

在低滞后时间期间,避免分配大量内存。

可能会出现内存不足通知,因为垃圾回收所回收的对象较少。

在低滞后时间模式下,最大限度地减少所进行的分配次数,特别是向大型对象堆和固定对象所做的分配。

请注意可能正在进行分配的线程。

由于LatencyMode属性设置是针对整个进程的,因此也许会在任何可能正在分配的线程上产生OutOfMemoryException。

将低滞后时间代码包装在受约束的执行区域中(有关更多信息,请参见受约束的执行区域)。

可以通过调用GC.Collect(Int32,GCCollectionMode)方法在低滞后时间期间强制进行第2代回收。

针对共享Web宿主优化

如果您是通过承载若干个小型网站来共享的服务器的管理员,则可向.NETFramework目录下Aspnet.config文件中的runtime节点中添加以下gcTrimCommitOnLowMemory设置,以优化性能并增加网站容量:

说明:

建议只将此设置用于共享Web宿主的情况。

由于垃圾回收器会保留内存以供将来分配,因此其提交空间可能多于真正需要的空间。

可以减小此空间,以适应系统内存负载较大的情况。

减小此提交空间可以提高性能并扩展容量,以承载更多站点。

启用gcTrimCommitOnLowMemory设置后,垃圾回收器将评估系统内存负载,并在负载达到90%时进入修整模式。

垃圾回收器将一直处于修整模式,直到负载下降到85%以下。

当情况允许时,垃圾回收器可以确定gcTrimCommitOnLowMemory设置对当前应用程序没有帮助,并将其忽略。

示例

下面的XML片段演示如何启用gcTrimCommitOnLowMemory设置。

椭圆指示将在runtime节点中的其他设置。

xmlversion="1.0"encoding="UTF-8"?

>

...

...

 

垃圾回收通知

公共语言运行时执行的完整垃圾回收有时可能会对性能产生负面影响。

对于处理大量请求的服务器而言,这个问题尤为突出;在这种情况下,长时间的垃圾回收可能会导致请求超时。

若要防止在重要时间段发生完整垃圾回收,可以让系统通知您即将发生完整垃圾回收,然后您可以采取措施将工作负荷重定向到其他服务器实例。

您也可以在当前服务器实例不需要处理请求时自己引发回收。

说明:

仅当禁用并发垃圾回收时才能使用此功能。

默认情况下会启用并发垃圾回收,除非您在宿主环境中运行应用程序且宿主已为您更改了该配置。

在使用服务器垃圾回收时,并发垃圾回收不可用。

此功能不支持并发垃圾回收,原因是在进行并发垃圾回收期间允许进行内存分配。

有关如何禁用并发垃圾回收的信息,请参见运行时设置。

有关垃圾回收的更多信息请参照这里

 

清理非托管资源

通过将对象的范围限制为protected,您可以防止应用程序用户直接调用对象的Finalize方法。

除此之外,我们强烈建议您不要直接从应用程序代码中调用非基类的类的Finalize方法。

为适当释放非托管资源,建议您实现公共的Dispose或Close方法,这两个方法可为对象执行必要的清理代码操作。

IDisposable接口为实现接口的资源类提供Dispose方法。

因为Dispose方法是公共的,所以应用程序用户可以直接调用该方法来释放非托管资源占用的内存。

在正确实现Dispose方法时,Finalize方法在未能调用Dispose方法的情况下充当防护措施来清理资源。

有关正确实现的更多信息,请参见实现Dispose方法。

本节内容

实现Dispose方法

描述用于释放非托管资源的Dispose方法的实现。

重写Finalize方法

描述Finalize和Dispose方法的合作方式。

C#中的析构函数语法

描述Finalize方法在C#中的等效方法。

使用封装资源的对象

描述确保Dispose方法得到调用的方式,例如C#using语句(在VisualBasic中为Using)。

 

实现Dispose方法

释放对象的模式(称为释放模式)对对象的生存期进行规定。

类型的Dispose方法应释放它拥有的所有资源。

它还应该通过调用其父类型的Dispose方法释放其基类型拥有的所有资源。

父类型的Dispose方法应该释放它拥有的所有资源,进而调用其父类型的Dispose方法,从而在整个基类型层次结构中传播此模式。

若要帮助确保始终正确地清理资源,Dispose方法应该可以多次调用而不引发异常。

对只使用托管资源的类型(如数组)实现Dispose方法并不能提高性能,原因是这些类型由垃圾回收器自动回收。

应主要对使用本机资源的托管对象和向.NETFramework公开的COM对象使用Dispose方法。

使用本机资源的托管对象(如FileStream类)实现IDisposable接口。

重要说明:

C++程序员不应该使用本主题。

而应参见DestructorsandFinalizersinVisualC++。

在.NETFramework2.0版中,C++编译器为实现资源的确定性处置提供支持,并且不允许直接实现Dispose方法。

Dispose方法应为它要释放的对象调用SuppressFinalize方法。

如果对象当前在终止队列中,则SuppressFinalize会阻止调用其Finalize方法。

请记住,执行Finalize方法会降低性能。

如果Dispose方法已完成清理对象的工作,垃圾回收器就不必调用对象的Finalize方法。

为GC.KeepAlive方法提供的代码示例演示了强行垃圾回收如何在回收对象的成员仍在执行时引起终结器运行。

在较长的Dispose方法末尾最好调用KeepAlive方法。

参考代码-clsDispose.vb

 

重写Finalize方法

Finalize方法在未能调用Dispose方法的情况下充当防护措施来清理资源。

您应该只实现Finalize方法来清理非托管资源。

您不应该对托管对象实现Finalize方法,因为垃圾回收器会自动清理托管资源。

默认情况下,Object.Finalize方法不进行任何操作。

如果要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写此方法。

说明:

您无法在C#或C++编程语言中重写Finalize方法。

在C#中可使用析构函数语法实现Finalize方法。

在.NETFramework2.0版中,C++为实现Finalize方法提供了自己的语法,如DestructorsandFinalizersinVisualC++中所述。

在早期版本中,C++与C#一样也使用析构函数语法来实现Finalize方法。

Object.Finalize方法的范围是受保护的。

当在类中重写该方法时,您应该保持这个有限的范围。

通过保护Finalize方法,您可以防止应用程序的用户直接调用对象的Finalize方法。

对象的Finalize方法应该释放该对象保留的所有资源。

它还应该调用该对象基类的Finalize方法。

对象的Finalize方法不应对任何非其基类的对象调用方法。

这是因为被调用的其他对象可能和调用对象在同一时间被回收,例如公共语言运行库关闭这种情况。

如果您允许任何异常避开Finalize方法,系统将认为方法返回,并继续调用其他对象的Finalize方法。

 

C#中的析构函数语法

您无法从C#或C++编程语言中调用或重写Object.Finalize方法。

C#将析构函数用作编写终止代码的机制,如析构函数(C#编程指南)中所述。

在C++中,析构函数语法用于实现Dispose方法。

C++为实现Finalize方法提供了自己的语法,如DestructorsandFinalizersinVisualC++中所述。

说明:

在.NETFramework2.0版之前,C++与C#一样也使用析构函数用法来实现Finalize方法,当时没有特殊语法来实现Dispose方法。

若要编译使用早期语法的C++代码,请使用/clr:

oldSyntax编译器选项。

尽管看起来相似,但C#和C++析构函数的语义与未托管C++析构函数的语义并不相同。

托管代码不支持任何与C++析构函数语义相似的语义。

 

使用封装资源的对象

如果您要编写代码,而该代码使用一个封装资源的对象,您应该确保在使用完该对象时调用该对象的Dispose方法。

要做到这一点,可以使用C#的using语句,或使用其他面向公共语言运行库的语言来实现try/finally块。

C#的Using语句

C#编程语言的using语句通过简化必须编写以便创建和清理对象的代码,使得对Dispose方法的调用更加自动化。

using语句获得一个或多个资源,执行您指定的语句,然后处置对象。

请注意,using语句只适用于这样的对象:

这些对象的生存期不超过在其中构建这些对象的方法。

下面的代码示例将创建并清理ResourceWrapper类的实例,如C#示例实现Dispose方法中所示。

ClassmyApp

{

publicstaticvoidMain()

{

using(ResourceWrapperr1=newResourceWrapper())

{

//Dosomethingwiththeobject.

r1.DoSomething();

}

}

}

以上合并了using语句的代码与下面的代码等效。

ClassmyApp

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1