自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

淺析提高.NET垃圾回收性能的幾種方法

開(kāi)發(fā) 后端
這里將分析提高.NET垃圾回收性能的幾種方法,并詳細(xì)介紹.NET垃圾回收機(jī)制,希望能對(duì)大家有所幫助。

對(duì)于GC垃圾回收,很多人不會(huì)陌生。我們這里講的是提高.NET垃圾回收機(jī)制性能的幾種方法,通過(guò)研究.NET垃圾回收機(jī)制,可以提高程序執(zhí)行效率。

本文值得閱讀嗎?

通過(guò)本文你會(huì)理解如何通過(guò)finalize dispose模式提升GC算法的性能。下圖顯示完成.NET垃圾回收機(jī)制優(yōu)化后的對(duì)比。

完成本文后的對(duì)比

介紹和目標(biāo)

問(wèn)一下每一個(gè)開(kāi)發(fā)人員,在.Net類(lèi)中清除非托管資源的***位置在哪里?他們中的70%的人員會(huì)說(shuō)放在析構(gòu)函數(shù)。盡管看起來(lái)好象是最有希望的位置,但那對(duì)性能和內(nèi)存消耗有巨大的影響。在析構(gòu)函數(shù)中寫(xiě)清理代碼會(huì)導(dǎo)致垃圾回收器再次調(diào)用,而且多次(multifold times)影響性能。

為了驗(yàn)證上面所說(shuō),我們先從理論開(kāi)始,然后我們會(huì)真實(shí)的看到使用析構(gòu)函數(shù)時(shí)如何影響性能。因此我們要理解世代的概念,然后再去看finalize dispose模式。

我相信本文會(huì)改變你關(guān)于析構(gòu)函數(shù)、dispose 和 finalize處理的看法。

請(qǐng)隨時(shí)到 http://www.questpond.com下載我的涵蓋.NET、 ASP.NET、 SQLServer、 WCF、 WPF、WWF的免費(fèi)500個(gè)問(wèn)題和回答的電子書(shū)。

假設(shè)

本文使用CLR探測(cè)器來(lái)探測(cè)GC如何工作。如果你對(duì)CLR探測(cè)器不熟悉,在繼續(xù)之前請(qǐng)先閱讀DOTNET1.aspx。

感謝Jeffrey Richter 和 Peter Sollich 先生

讓我們以感謝Jeffery Richter作為本文的開(kāi)始,因?yàn)樗钊氲慕忉屃死厥账惴ㄈ绾喂ぷ?。他曾?jīng)寫(xiě)過(guò)兩個(gè)關(guān)于垃圾回收工作方式的傳奇文章。我很想指出Jeffery Richter在MSDN雜志寫(xiě)的文章,但因?yàn)橐恍┰虿](méi)有在MSDN顯示出來(lái)。所以我給出一個(gè)非官方的地址,你可以從http://www.cs.inf.ethz.ch/ssw/files/GC_in_NET.pdf下載PDF格式文章。

同時(shí)也感謝Peter Sollich先生,他是CLR性能框架師,為CLR探測(cè)器寫(xiě)了詳細(xì)的幫助。當(dāng)你安裝CLR探測(cè)器時(shí),請(qǐng)不要忘記閱讀Peter Sollich寫(xiě)的詳細(xì)幫助文檔。在本文中我們會(huì)使用CLR探測(cè)器驗(yàn)證使用finalize對(duì)垃圾回收器性能的影響。

非常感謝你們的支持,如果沒(méi)有讀你們寫(xiě)的文章,我就不能完成這篇文章,無(wú)論何時(shí)我都很樂(lè)意聽(tīng)到你們閱讀文章的評(píng)論。

垃圾回收器-幕后英雄

如在介紹中所說(shuō),把清理代碼放在析構(gòu)函數(shù)會(huì)導(dǎo)致垃圾回收器的兩次調(diào)用。許多開(kāi)發(fā)人員會(huì)聳聳肩說(shuō)“我們真的需要去關(guān)心垃圾回收器(GC)在后臺(tái)做了什么嗎?”,對(duì),如果你寫(xiě)合適的代碼,我們確實(shí)不需要關(guān)心垃圾回收。垃圾回收器有保證你的應(yīng)用程序不受影響的***的算法。但是很多時(shí)候,你寫(xiě)代碼的方式和在你代碼中分配/清理內(nèi)存資源的方式對(duì)垃圾回收算法產(chǎn)生了較大的影響。有時(shí)這種影響會(huì)導(dǎo)致垃圾回收器(GC)很差的性能,進(jìn)而導(dǎo)致你應(yīng)用程序很差的的性能。

因此我們先來(lái)看一下在垃圾回收器分配和清理內(nèi)存時(shí)都執(zhí)行了哪些不同的任務(wù)。

假如我們有三個(gè)類(lèi),類(lèi)A調(diào)用了類(lèi)B,類(lèi)B調(diào)用了類(lèi)C。

垃圾回收器分配和清理內(nèi)存

當(dāng)應(yīng)用程序***次執(zhí)行時(shí),預(yù)定義內(nèi)存分配給應(yīng)用程序。當(dāng)應(yīng)用程序創(chuàng)建這3個(gè)對(duì)象時(shí),它們被賦于一個(gè)內(nèi)存棧上的地址。你可以從下圖中看到對(duì)象創(chuàng)建之前和對(duì)象創(chuàng)建之后的內(nèi)存的樣子。如果還有一個(gè)對(duì)象D要?jiǎng)?chuàng)建,它會(huì)從對(duì)象C結(jié)束處分配地址。

對(duì)象創(chuàng)建之前和對(duì)象創(chuàng)建之后的內(nèi)存

在內(nèi)部,垃圾回收器為了知道哪些對(duì)象是可達(dá)的要維護(hù)一個(gè)對(duì)象圖。所有的對(duì)象屬于主應(yīng)用程序的根對(duì)象,根對(duì)象同樣維護(hù)著哪些對(duì)象分配了哪些內(nèi)存地址。如果一個(gè)對(duì)象使用了其他的對(duì)象,那么這個(gè)對(duì)象也要保存它使用的對(duì)象的內(nèi)存地址。例如,在我們的示例中的對(duì)象A使用了對(duì)象B,所以對(duì)象A保存了對(duì)象B的內(nèi)存地址。

對(duì)象圖

現(xiàn)在假如對(duì)象A從內(nèi)存中移除,那么對(duì)象A的內(nèi)存被賦于了對(duì)象B,對(duì)象B的內(nèi)存被賦于了對(duì)象C。內(nèi)部的內(nèi)存分配情況如下所示:

內(nèi)部的內(nèi)存分配

隨同內(nèi)存指針的更新,垃圾回收器需要確保它的內(nèi)部對(duì)象圖也隨著新的內(nèi)存地址更新了。因此對(duì)象圖變成了如下所示的樣子。對(duì)垃圾回收器有一些工作要做,它需要確保已經(jīng)不再使用的對(duì)象已經(jīng)從圖中移除,并且還存在的對(duì)象的地址已經(jīng)在對(duì)象樹(shù)中全部更新了。

對(duì)象圖

除應(yīng)用程序自定義對(duì)象外,構(gòu)成對(duì)象圖表的還有.Net對(duì)象,那些對(duì)象的地址也是要更新的。.Net運(yùn)行時(shí)對(duì)象的數(shù)量非常大,下圖就是一個(gè)簡(jiǎn)單的Hello World控制臺(tái)應(yīng)用程序創(chuàng)建的對(duì)象的數(shù)量,對(duì)象的數(shù)量約有1000個(gè),更新每一個(gè)對(duì)象的指針是一個(gè)很大的任務(wù)。

Hello World控制臺(tái)

世代算法今天、昨天和前天

GC(垃圾回收器)使用世代的概念來(lái)提升性能。世代的概念是基于人們處理事情的心理的方式。下面的幾點(diǎn)指出人們是如何處理事情的,并且垃圾回收算法是按相同的方式工作:

如果你今天決定要做一些事情,那么很可能今天就把這些事做完。

如果一些事是昨天未決定的,那么很可能這些事情會(huì)給予比較低的優(yōu)先級(jí)并且被再一次推遲。

如果一些事是前天未決定的,那么就有很大的可能性這個(gè)事被永遠(yuǎn)推遲。

GC以同樣的方式思考并且使用下面的假設(shè):

如果一個(gè)對(duì)象是新創(chuàng)建的,那么它的生命期可能很短。

如果一個(gè)對(duì)象是原來(lái)存在的,它可能會(huì)有更長(zhǎng)的生命。

所以說(shuō),GC做了三個(gè)世代的支持(0代,1代和2)。

三個(gè)世代的支持

0代包括所有新創(chuàng)建的對(duì)象,當(dāng)應(yīng)用程序創(chuàng)建對(duì)象時(shí),這些對(duì)象首先被放入0代對(duì)象列表中。當(dāng)0代對(duì)象裝滿時(shí),GC需要運(yùn)行以釋放內(nèi)存資源,GC開(kāi)始構(gòu)建圖表并刪除所有應(yīng)用程序不再使用的對(duì)象。如果一個(gè)對(duì)象GC不能在0代刪除,那么該對(duì)象會(huì)被提升為1代。如果在后面的迭代中一個(gè)對(duì)象不能在1代中刪除,那么它會(huì)被提升為2代。.Net運(yùn)行時(shí)支持的***代是2代。

下面是當(dāng)你運(yùn)行CLR探測(cè)器時(shí)關(guān)于世代對(duì)象的一個(gè)簡(jiǎn)單顯示。如果你對(duì)CLR探測(cè)器不了解,請(qǐng)先從DOTNET1.aspx了解CLR的基本知識(shí)。

運(yùn)行CLR探測(cè)器

那么,在優(yōu)化中世代有什么幫助呢

作為世代中的對(duì)象,GC會(huì)對(duì)哪個(gè)世代的對(duì)象需要被清理做出選擇。如果你記得,前面小節(jié)中我們講過(guò)關(guān)于GC認(rèn)定對(duì)象世代的假設(shè),GC假設(shè)新對(duì)象具有更短的生命周期。換句話說(shuō),GC主要檢查0代的對(duì)象,而不是所有世代的所有對(duì)象。

如果清理0代對(duì)象不能提供足夠的內(nèi)存,它將繼而清理1代的對(duì)象,并依次繼續(xù)。這個(gè)算法能大幅提升GC的性能。

關(guān)于世代的推論

如果有大量的對(duì)象在1代或2代區(qū)域則說(shuō)明內(nèi)存使用沒(méi)有優(yōu)化。

更大的世代1和世代2區(qū)域會(huì)導(dǎo)致GC算法性能更差。

使用終結(jié)器(finalize)/析構(gòu)函數(shù)會(huì)導(dǎo)致更多的1代和2代對(duì)象

C#編譯器會(huì)把析構(gòu)函數(shù)翻譯(重命名)為終結(jié)器。如果你使用IDASM查看IL代碼,就會(huì)看到析構(gòu)函數(shù)被重命名為終結(jié)器(finalize)。所以讓我們先理解為什么實(shí)現(xiàn)析構(gòu)函數(shù)會(huì)導(dǎo)致更多的對(duì)象進(jìn)入1代和2代區(qū)域?,F(xiàn)在來(lái)看處理器是如何工作的:

當(dāng)新對(duì)象創(chuàng)建時(shí),它們被放到0代。

當(dāng)0代區(qū)域填滿時(shí),GC運(yùn)行并清理內(nèi)存。

如果對(duì)象沒(méi)有析構(gòu)函數(shù),那么如果它們不再被使用,GC就把它們清理掉。

如果對(duì)象有終結(jié)(finalize)方法,GC就把它們放到終結(jié)隊(duì)列中。

如果對(duì)象是可達(dá)的,它會(huì)被放置到Freachable隊(duì)列中,如果對(duì)象是不可達(dá)的,內(nèi)存將被收回。

GC完成本次迭代工作。

下一次當(dāng)GC開(kāi)始工作時(shí),它會(huì)進(jìn)入Freachable隊(duì)列檢查對(duì)象是否可達(dá),如果Freachable中的對(duì)象不可達(dá),內(nèi)存就會(huì)被聲名為可收回的。

析構(gòu)函數(shù)的對(duì)象

換句話說(shuō),有析構(gòu)函數(shù)的對(duì)象會(huì)在內(nèi)存中存活更長(zhǎng)的時(shí)間。

讓我們來(lái)看下實(shí)際的情況,下面是一個(gè)簡(jiǎn)單的有析構(gòu)函數(shù)的類(lèi)。

  1. class clsMyClass
  2. {
  3. public clsMyClass()
  4. {
  5. }
  6. ~clsMyClass()
  7. {
  8. }
  9. }

讓我們用CLR探測(cè)器來(lái)監(jiān)視創(chuàng)建100*10000個(gè)對(duì)象時(shí)的情況。

  1. for (int i = 0; i < 100 * 10000; i++)
  2. {
  3. clsMyClass obj = new clsMyClass();
  4. }

如果使用CLR探測(cè)器的內(nèi)存地址報(bào)表,會(huì)看到大量的對(duì)象在1代。

CLR探測(cè)器的內(nèi)存地址報(bào)表

現(xiàn)在去掉析構(gòu)函數(shù)后再做一遍。

  1. class clsMyClass
  2. {
  3. public clsMyClass()
  4. {
  5. }
  6. }

你可以看到在0代對(duì)象大量增加,同時(shí)1代和2代對(duì)象很少。

0代對(duì)象

如果做一對(duì)一的對(duì)比,結(jié)果如下圖所示:

做一對(duì)一的對(duì)比

#p#

使用Dispose代替去掉的析構(gòu)函數(shù)

我們可以去掉析構(gòu)函數(shù)而在dispose方法中實(shí)現(xiàn)清理代碼。為此要實(shí)現(xiàn)‘IDisposable’ 的接口方法,在這寫(xiě)我們的清理代碼,并如下代碼段所示調(diào)用終結(jié)方法。

‘SuppressFinalize’指示GC不要調(diào)用finalize方法,所以不會(huì)發(fā)生GC的二次調(diào)用。

  1. class clsMyClass : IDisposable
  2. {
  3. public clsMyClass()
  4. {
  5. }
  6. ~clsMyClass()
  7. {
  8. }
  9. public void Dispose()
  10. {
  11. GC.SuppressFinalize(this);
  12. }
  13. }
現(xiàn)在客戶端要確保它要象如下所示調(diào)用dispose方法。
  1. for (int i = 0; i < 100 ; i++)
  2. {
  3. clsMyClass obj = new clsMyClass();
  4. obj.Dispose();
  5. }
下圖是使用析構(gòu)函數(shù)和使用dispose時(shí)的0代和1代對(duì)象如何分布的對(duì)比。你會(huì)看到0代內(nèi)存分配有明顯的提升,這標(biāo)識(shí)著更好的內(nèi)存分配。

內(nèi)存分布對(duì)比

如果開(kāi)發(fā)人員忘記調(diào)用Dispose

這不是一個(gè)***的世界,我們不能確保在客戶端總是調(diào)用了dispose方法。這就是下面的小節(jié)中我們要使用Finalize / Dispose模式的原因。

關(guān)于這個(gè)模式在http://msdn.microsoft.com/en-us/library/b1yfkh5e(VS.71).aspx.有詳細(xì)的實(shí)現(xiàn)。

下面看起來(lái)更象是如何實(shí)現(xiàn)finalize / dispose模式。

  1. class clsMyClass : IDisposable
  2. {
  3. public clsMyClass()
  4. {
  5. }
  6. ~clsMyClass()
  7. {
  8. // In case the client forgets to call
  9. // Dispose , destructor will be invoked for
  10. Dispose(false);
  11. }
  12. protected virtual void Dispose(bool disposing)
  13. {
  14. if (disposing)
  15. {
  16. // Free managed objects.
  17. }
  18. // Free unmanaged objects
  19. }
  20. public void Dispose()
  21. {
  22. Dispose(true);
  23. // Ensure that the destructor is not called
  24. GC.SuppressFinalize(this);
  25. }
  26. }

代碼解釋?zhuān)?/STRONG>

我們定義了一個(gè)帶布爾參數(shù)的Dispose方法,該參數(shù)說(shuō)明是從Dispose中調(diào)用還是從析構(gòu)函數(shù)中調(diào)用。如果是從’Dispose’方法調(diào)用,則釋放所有的托管和非托管的資源。

如果該方法是從析構(gòu)函數(shù)中調(diào)用,則只釋放非托管的資源。

在dispose方法中我們禁用了finilize的調(diào)用,并且用true參數(shù)調(diào)用了這個(gè)dispose方法。

在析構(gòu)函數(shù)中我們使用false值調(diào)用dispose函數(shù)。換句話說(shuō),我們假定GC會(huì)處理好托管的資源并用析構(gòu)函數(shù)調(diào)用來(lái)清理非托管資源。

換句話說(shuō),客戶端沒(méi)有調(diào)用dispose函數(shù),析構(gòu)函數(shù)會(huì)照顧清除非托管資源。

結(jié)論

不要在類(lèi)中寫(xiě)空的析構(gòu)函數(shù)。

如果你需要清除,使用帶‘SupressFinalize’方法調(diào)用的finalize dispose模式。

如果類(lèi)有公開(kāi)的dispose方法,確保在客戶端代碼中調(diào)用它。

應(yīng)用程序應(yīng)該分配在0代區(qū)域中的對(duì)象比分配在1代和2代區(qū)域中的對(duì)象更多。如果在1代和2代區(qū)域中有更多的對(duì)象,標(biāo)志著很差的GC算法執(zhí)行。

源代碼

可以在這里找到dispose模式的示例代碼

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Shivprasad koirala

[[6016]]


Member

原文標(biāo)題:.net***實(shí)踐二:使用finalize/dispose模式提升垃圾回收器性能

鏈接:http://www.cnblogs.com/mickeychang/archive/2009/09/17/1568670.html

【編輯推薦】

  1. 簡(jiǎn)述C# XML解析方法的特點(diǎn)及應(yīng)用
  2. .NET對(duì)象的XML序列化和反序列化概念淺析
  3. .NET對(duì)象的XML序列化和反序列化實(shí)例詳解
  4. C# XML序列化實(shí)例淺析
  5. .NET序列化和反序列化基礎(chǔ)知識(shí)總結(jié)
責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2009-07-20 17:07:30

提高ASP.NET性能

2021-03-03 08:13:57

模式垃圾回收

2009-06-23 14:15:00

Java垃圾回收

2019-12-12 21:45:17

javascript前端css

2010-01-05 18:49:57

.NET Framew

2009-09-24 14:59:38

C#編寫(xiě)COM組件

2009-07-28 16:07:40

.NET圖片快速處理

2009-02-25 09:52:14

類(lèi)型轉(zhuǎn)換.NET 強(qiáng)制轉(zhuǎn)型

2012-12-18 13:57:42

.NetC#

2010-09-08 13:53:10

.NET連接Sybas

2009-09-04 11:20:47

ASP.NET頁(yè)面間值

2022-03-21 11:33:11

JVM垃圾回收器垃圾回收算法

2020-03-13 08:00:00

.NET對(duì)象清理垃圾回收

2009-10-14 14:37:56

調(diào)試.NET程序

2009-07-29 11:33:14

ASP.NET技巧ASP.NET應(yīng)用程序

2021-01-04 10:08:07

垃圾回收Java虛擬機(jī)

2021-11-25 07:01:57

.NET開(kāi)發(fā)編程

2022-01-20 10:34:49

JVM垃圾回收算法

2017-08-04 10:53:30

回收算法JVM垃圾回收器

2009-07-27 14:41:33

ASP.NET調(diào)用存儲(chǔ)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)