成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發 后端
這里將分析提高.NET垃圾回收性能的幾種方法,并詳細介紹.NET垃圾回收機制,希望能對大家有所幫助。

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

本文值得閱讀嗎?

通過本文你會理解如何通過finalize dispose模式提升GC算法的性能。下圖顯示完成.NET垃圾回收機制優化后的對比。

完成本文后的對比

介紹和目標

問一下每一個開發人員,在.Net類中清除非托管資源的***位置在哪里?他們中的70%的人員會說放在析構函數。盡管看起來好象是最有希望的位置,但那對性能和內存消耗有巨大的影響。在析構函數中寫清理代碼會導致垃圾回收器再次調用,而且多次(multifold times)影響性能。

為了驗證上面所說,我們先從理論開始,然后我們會真實的看到使用析構函數時如何影響性能。因此我們要理解世代的概念,然后再去看finalize dispose模式。

我相信本文會改變你關于析構函數、dispose 和 finalize處理的看法。

請隨時到 http://www.questpond.com下載我的涵蓋.NET、 ASP.NET、 SQLServer、 WCF、 WPF、WWF的免費500個問題和回答的電子書。

假設

本文使用CLR探測器來探測GC如何工作。如果你對CLR探測器不熟悉,在繼續之前請先閱讀DOTNET1.aspx。

感謝Jeffrey Richter 和 Peter Sollich 先生

讓我們以感謝Jeffery Richter作為本文的開始,因為他深入的解釋了垃圾回收算法如何工作。他曾經寫過兩個關于垃圾回收工作方式的傳奇文章。我很想指出Jeffery Richter在MSDN雜志寫的文章,但因為一些原因并沒有在MSDN顯示出來。所以我給出一個非官方的地址,你可以從http://www.cs.inf.ethz.ch/ssw/files/GC_in_NET.pdf下載PDF格式文章。

同時也感謝Peter Sollich先生,他是CLR性能框架師,為CLR探測器寫了詳細的幫助。當你安裝CLR探測器時,請不要忘記閱讀Peter Sollich寫的詳細幫助文檔。在本文中我們會使用CLR探測器驗證使用finalize對垃圾回收器性能的影響。

非常感謝你們的支持,如果沒有讀你們寫的文章,我就不能完成這篇文章,無論何時我都很樂意聽到你們閱讀文章的評論。

垃圾回收器-幕后英雄

如在介紹中所說,把清理代碼放在析構函數會導致垃圾回收器的兩次調用。許多開發人員會聳聳肩說“我們真的需要去關心垃圾回收器(GC)在后臺做了什么嗎?”,對,如果你寫合適的代碼,我們確實不需要關心垃圾回收。垃圾回收器有保證你的應用程序不受影響的***的算法。但是很多時候,你寫代碼的方式和在你代碼中分配/清理內存資源的方式對垃圾回收算法產生了較大的影響。有時這種影響會導致垃圾回收器(GC)很差的性能,進而導致你應用程序很差的的性能。

因此我們先來看一下在垃圾回收器分配和清理內存時都執行了哪些不同的任務。

假如我們有三個類,類A調用了類B,類B調用了類C。

垃圾回收器分配和清理內存

當應用程序***次執行時,預定義內存分配給應用程序。當應用程序創建這3個對象時,它們被賦于一個內存棧上的地址。你可以從下圖中看到對象創建之前和對象創建之后的內存的樣子。如果還有一個對象D要創建,它會從對象C結束處分配地址。

對象創建之前和對象創建之后的內存

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

對象圖

現在假如對象A從內存中移除,那么對象A的內存被賦于了對象B,對象B的內存被賦于了對象C。內部的內存分配情況如下所示:

內部的內存分配

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

對象圖

除應用程序自定義對象外,構成對象圖表的還有.Net對象,那些對象的地址也是要更新的。.Net運行時對象的數量非常大,下圖就是一個簡單的Hello World控制臺應用程序創建的對象的數量,對象的數量約有1000個,更新每一個對象的指針是一個很大的任務。

Hello World控制臺

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

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

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

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

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

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

如果一個對象是新創建的,那么它的生命期可能很短。

如果一個對象是原來存在的,它可能會有更長的生命。

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

三個世代的支持

0代包括所有新創建的對象,當應用程序創建對象時,這些對象首先被放入0代對象列表中。當0代對象裝滿時,GC需要運行以釋放內存資源,GC開始構建圖表并刪除所有應用程序不再使用的對象。如果一個對象GC不能在0代刪除,那么該對象會被提升為1代。如果在后面的迭代中一個對象不能在1代中刪除,那么它會被提升為2代。.Net運行時支持的***代是2代。

下面是當你運行CLR探測器時關于世代對象的一個簡單顯示。如果你對CLR探測器不了解,請先從DOTNET1.aspx了解CLR的基本知識。

運行CLR探測器

那么,在優化中世代有什么幫助呢

作為世代中的對象,GC會對哪個世代的對象需要被清理做出選擇。如果你記得,前面小節中我們講過關于GC認定對象世代的假設,GC假設新對象具有更短的生命周期。換句話說,GC主要檢查0代的對象,而不是所有世代的所有對象。

如果清理0代對象不能提供足夠的內存,它將繼而清理1代的對象,并依次繼續。這個算法能大幅提升GC的性能。

關于世代的推論

如果有大量的對象在1代或2代區域則說明內存使用沒有優化。

更大的世代1和世代2區域會導致GC算法性能更差。

使用終結器(finalize)/析構函數會導致更多的1代和2代對象

C#編譯器會把析構函數翻譯(重命名)為終結器。如果你使用IDASM查看IL代碼,就會看到析構函數被重命名為終結器(finalize)。所以讓我們先理解為什么實現析構函數會導致更多的對象進入1代和2代區域。現在來看處理器是如何工作的:

當新對象創建時,它們被放到0代。

當0代區域填滿時,GC運行并清理內存。

如果對象沒有析構函數,那么如果它們不再被使用,GC就把它們清理掉。

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

如果對象是可達的,它會被放置到Freachable隊列中,如果對象是不可達的,內存將被收回。

GC完成本次迭代工作。

下一次當GC開始工作時,它會進入Freachable隊列檢查對象是否可達,如果Freachable中的對象不可達,內存就會被聲名為可收回的。

析構函數的對象

換句話說,有析構函數的對象會在內存中存活更長的時間。

讓我們來看下實際的情況,下面是一個簡單的有析構函數的類。

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

讓我們用CLR探測器來監視創建100*10000個對象時的情況。

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

如果使用CLR探測器的內存地址報表,會看到大量的對象在1代。

CLR探測器的內存地址報表

現在去掉析構函數后再做一遍。

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

你可以看到在0代對象大量增加,同時1代和2代對象很少。

0代對象

如果做一對一的對比,結果如下圖所示:

做一對一的對比

#p#

使用Dispose代替去掉的析構函數

我們可以去掉析構函數而在dispose方法中實現清理代碼。為此要實現‘IDisposable’ 的接口方法,在這寫我們的清理代碼,并如下代碼段所示調用終結方法。

‘SuppressFinalize’指示GC不要調用finalize方法,所以不會發生GC的二次調用。

  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. }
現在客戶端要確保它要象如下所示調用dispose方法。
  1. for (int i = 0; i < 100 ; i++)
  2. {
  3. clsMyClass obj = new clsMyClass();
  4. obj.Dispose();
  5. }
下圖是使用析構函數和使用dispose時的0代和1代對象如何分布的對比。你會看到0代內存分配有明顯的提升,這標識著更好的內存分配。

內存分布對比

如果開發人員忘記調用Dispose

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

關于這個模式在http://msdn.microsoft.com/en-us/library/b1yfkh5e(VS.71).aspx.有詳細的實現。

下面看起來更象是如何實現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. }

代碼解釋:

我們定義了一個帶布爾參數的Dispose方法,該參數說明是從Dispose中調用還是從析構函數中調用。如果是從’Dispose’方法調用,則釋放所有的托管和非托管的資源。

如果該方法是從析構函數中調用,則只釋放非托管的資源。

在dispose方法中我們禁用了finilize的調用,并且用true參數調用了這個dispose方法。

在析構函數中我們使用false值調用dispose函數。換句話說,我們假定GC會處理好托管的資源并用析構函數調用來清理非托管資源。

換句話說,客戶端沒有調用dispose函數,析構函數會照顧清除非托管資源。

結論

不要在類中寫空的析構函數。

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

如果類有公開的dispose方法,確保在客戶端代碼中調用它。

應用程序應該分配在0代區域中的對象比分配在1代和2代區域中的對象更多。如果在1代和2代區域中有更多的對象,標志著很差的GC算法執行。

源代碼

可以在這里找到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

原文標題:.net***實踐二:使用finalize/dispose模式提升垃圾回收器性能

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

【編輯推薦】

  1. 簡述C# XML解析方法的特點及應用
  2. .NET對象的XML序列化和反序列化概念淺析
  3. .NET對象的XML序列化和反序列化實例詳解
  4. C# XML序列化實例淺析
  5. .NET序列化和反序列化基礎知識總結
責任編輯:彭凡 來源: 博客園
相關推薦

2009-07-20 17:07:30

提高ASP.NET性能

2021-03-03 08:13:57

模式垃圾回收

2009-06-23 14:15:00

Java垃圾回收

2009-09-24 14:59:38

C#編寫COM組件

2019-12-12 21:45:17

javascript前端css

2010-01-05 18:49:57

.NET Framew

2009-07-28 16:07:40

.NET圖片快速處理

2009-02-25 09:52:14

類型轉換.NET 強制轉型

2010-09-08 13:53:10

.NET連接Sybas

2012-12-18 13:57:42

.NetC#

2009-09-04 11:20:47

ASP.NET頁面間值

2009-10-14 14:37:56

調試.NET程序

2022-03-21 11:33:11

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

2009-07-03 13:22:37

調用Servlet

2020-03-13 08:00:00

.NET對象清理垃圾回收

2009-07-27 14:41:33

ASP.NET調用存儲

2021-11-25 07:01:57

.NET開發編程

2009-07-29 11:33:14

ASP.NET技巧ASP.NET應用程序

2011-05-24 15:15:12

mysql性能

2009-07-24 16:40:14

ASP.NET軟件開發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美亚洲视频 | 久草网站 | 夜夜夜操 | 中文日韩在线 | 天堂在线91| 欧美精品一区二区三区在线播放 | 日日碰碰 | 国产精品区二区三区日本 | 天天干天天爱天天 | 高清国产午夜精品久久久久久 | 欧美一区二区三区小说 | 国产精品久久久久aaaa樱花 | 久热久热 | 中文字幕免费中文 | 国产激情精品视频 | 日韩精品一区二区三区视频播放 | 亚洲国产成人在线视频 | 国产精品揄拍一区二区久久国内亚洲精 | 日本午夜精品 | 亚洲精品视频免费观看 | 国产视频一区二区三区四区五区 | 午夜电影网 | av在线天堂| 欧洲视频一区二区 | 中文字幕亚洲视频 | 在线观看午夜视频 | 特级一级黄色片 | 网站黄色在线 | 国产a区| 欧美激情第一区 | 亚洲第一女人av | 国产午夜精品久久久 | 国际精品鲁一鲁一区二区小说 | 91久久精品一区二区二区 | 一区二区视频在线观看 | 国产日产精品一区二区三区四区 | 国产成人99久久亚洲综合精品 | 天天拍天天射 | 日韩免费看视频 | 欧美日韩综合一区 | 国产视频一区在线观看 |