999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?

淺析.NET的垃圾回收機制

2008-12-31 00:00:00李艷會
電腦知識與技術 2008年34期

摘要:.NET Framework中的垃圾回收(Garbage Collection)機制減少了一些應用程序中發(fā)生內(nèi)存泄露和訪問沖突的可能性,但GC的工作機制仍然存在問題。在程序開發(fā)中,總會發(fā)現(xiàn)對于GC的錯誤理解。文章針對此問題進行研究分析,簡要說明內(nèi)存垃圾的產(chǎn)生原因、垃圾回收機制的原理、垃圾回收的主要對象以及釋放模式。

關鍵詞:內(nèi)存管理;托管堆;垃圾回收;釋放模式;終結器

中圖分類號:TP311 文獻標識碼:A文章編號:1009-3044(2008)34-1989-03

Analyst of the Garbage Collection System of .NET

SHI Jun, LI Yan-hui

(Computer Science and Technology Department, Yangzhou Vocational College of Environment Resources, Yangzhou 225127, China)

Abstract: The garbage collection (GC) system of .NET Framework is to reduce the possibility of memory leak and access violation from some application programs, but the problem still exists because of the working system of the GC. It is always found the GC to be misunderstood during the program development. Based on the analysis of this problem, this article is going to explain briefly the root cause of memory garbage, the theory of the garbage collection system, its main objective and release mode.

Key words: memory management; managed heap; garbage collection; release mode; finalizer

1 引言

我們可能都碰到過程序莫名奇妙的崩潰、或內(nèi)存使用不停上漲。對于前者,常見的有資源管理器突然崩潰,機器突然發(fā)生藍屏;對于后者,你可能會發(fā)現(xiàn)有些進程的內(nèi)存持續(xù)暴漲,直到計算機無法使用,這時不得不重啟計算機,這就是常見的訪問沖突和內(nèi)存泄漏。

相對于C++程序員來說,C#程序員非常幸運,至少不要為內(nèi)存泄漏而頭疼,不需要負責內(nèi)存的分配和回收。不少程序員都會有這樣的疑惑:內(nèi)存分配和釋放由.NET Framework進行,但能保證內(nèi)存的有效使用嗎?能夠保證程序的運行效率嗎?

2 垃圾回收機制

在.NET Framework中,內(nèi)存中的資源分為\"托管資源\"和\"非托管資源\"。托管資源必須接受CLR(公共語言運行庫)的管理,分別存放在兩種地方:\"堆棧\"和\"托管堆\";規(guī)則是,所有的值類型(包括引用和對象實例)和引用類型的引用都存放在\"堆棧\"中,而所有引用所代表的對象實例都保存在托管堆中。而非托管資源則不必接受CLR的管理。

內(nèi)存管理就是對象的分配和釋放問題。在傳統(tǒng)的Win32編程中,對于資源對象的訪問方式是:

1) 聲明對象并分配內(nèi)存;

2) 使用對象;

3) 銷毀對象并釋放內(nèi)存。

上面的每一步,可能都存在陷阱。可能內(nèi)存不夠用,導致下面的代碼調(diào)試失敗;可能要訪問的對象,指向了一個虛無縹緲的地址空間;可能編程人員忘記了釋放內(nèi)存,會發(fā)生內(nèi)存泄漏,也有一些編程人員試圖訪問已經(jīng)被釋放的內(nèi)存,那么也會發(fā)生訪問沖突。我們以前使用的C++語言或其它語言,它們的對象是創(chuàng)建在非托管堆之上的。對于非托管編程來說,Bug發(fā)生的時間和次序都難以預測,所以對應用程序來說,它們所帶來的危害,遠遠超過了其他大多數(shù)的Bug,這使得應用程序的運行結果變得不可預測。

在.NET Framework中,對象是創(chuàng)建在托管堆之上的,上述的一切問題,在托管堆編程中,這種情況得到了極大的改善,回收內(nèi)存的工作不需要再用編程人員區(qū)操心了。.NET提供了一種自動垃圾回收機制,這就是Garbage Collection(簡稱GC)。垃圾回收器管理著應用程序的內(nèi)存分配和釋放。每次使用new運算符創(chuàng)建對象時,運行庫都從托管堆為該對象分配內(nèi)存。只要托管堆中有地址空間可用,運行庫就會繼續(xù)為新對象分配空間。

.NET中的垃圾回收機制非常先進,它使得我們更加專注于應用程序的邏輯,垃圾回收機制中,首先要了解對象的生存期,也就是對象什么時候變成垃圾。我們討論的只是托管堆上對象的生存期,而不是堆棧上的對象,因為隨著堆棧的自動回收,該對象就結束了生命。

3 垃圾回收原理

3.1 托管堆對象的處理

在.NET中,引用對象分配在托管堆上的,值對象分配在引用程序自身的堆棧上。在托管堆中,每個對象都是在內(nèi)存中是連續(xù)的,中間沒有空隙。見圖1(a)所示,如果對象B被釋放了,那么托管堆會變成圖1(b)的樣子,這個過程,我們可以稱之為標記壓縮過程。即標記對象B為垃圾,調(diào)用適當?shù)姆椒ǎ袯占用的內(nèi)存釋放,然后移動對象C到A的身邊,內(nèi)存空間被壓縮了。

如果每個對象被釋放,都執(zhí)行一次標記壓縮過程,那么對于性能的影響是非常大的。GC將托管堆劃分為三個代,即第0/1/2代。在托管堆被初始化的時候,托管堆中不包含任何對象,這時添加到托管堆中的對象稱之為第0代,各個對象在內(nèi)存中是連續(xù)的。在CLR被初始化時,它會為第0代選擇一個預算的容量,一般是256KB,因為這樣可以把第0代對象裝入CPU的L2 Cache中,這樣使內(nèi)存壓出速度非常快。對于每個代,都會有一個初始值,一般是:256K/2M/10M(注:此值和代數(shù)的個數(shù)在不同版本的CLR可能不同)。

如圖2,我們舉例來分析一下各個代垃圾回收的工作原理。

1) 假設有A~E五個對象,共為256K,存放于托管堆的第0代對象中。某時刻,C和E成為垃圾(圖2(a))。假設要創(chuàng)建F,此時第0代已滿,進行垃圾回收。釋放C和E后,壓縮內(nèi)存,以保證對象的連續(xù)性,經(jīng)歷了第一輪垃圾回收后,第0代變成了第1代。

2) 創(chuàng)建FGHIJK對象后,接下來B、H和J相繼成為垃圾(圖2(b))。假設要創(chuàng)建L,這時第0代占滿,所以進行第二次垃圾回收。當GC工作時,先查看第1代占用了多少內(nèi)存,本例中,第1代占用的內(nèi)存遠遠小于2M。所以,這次垃圾收集僅僅檢查第0代,H和J釋放,B并不釋放。壓縮內(nèi)存,F(xiàn)GIK都變成了第1代。很明顯,在第1代內(nèi)存空間未滿時,忽略對它的檢查,可以改善GC的性能。

3) 這時在第0代上又創(chuàng)建了LMNO對象,后來GLM也變成了垃圾(圖2(c))。

4) 這時創(chuàng)建P,第0代占滿,所以GC又被啟動了,這時第1代的空間仍然小于2M,所以GC只回收第0代,第1代的空間逐漸變大。創(chuàng)建PQRS對象后,這時,AKPR相繼成為垃圾,隨著程序的運行,更多的對象成為垃圾(圖2(d))。

5) 假定經(jīng)過三次垃圾回收之后,第1代的空間已經(jīng)超出2M,而當時垃圾回收剛完成,所以不立刻對第1代進行回收。在第四次回收之前,發(fā)現(xiàn)第1代的空間超出2M,這時對第1代和第0代同時進行垃圾回收。先回收第1代的垃圾,第1代變成了第2代,第0代的對象變?yōu)榈?代(圖2(e))。

只要第2代10M空間未滿,就不會對它進行垃圾回收。也就是說,第2代的垃圾回收的頻率最低,第1代次之,第0代最高。

CLR的GC是一個自調(diào)節(jié)的垃圾收集器,這意味著,GC會在執(zhí)行垃圾收集的過程中,學習應用程序的行為,它可以根據(jù)應用程序的實際情況,將第0代的容量從256K減到128K,從而提高程序的性能。這些工作是由CLR自動完成的,不需要程序員寫任何代碼。

3.2 非托管對象的處理

對于非托管對象,一旦程序不再使用該對象,就必須采取嚴格的方式來釋放資源。如無法釋放,會導致資源泄漏,有可能耗盡可用資源,防礙程序的繼續(xù)執(zhí)行。在CLR中,每個類型都必須提供一個Finalize方法。垃圾回收時,將執(zhí)行該類型的Finalize方法,對非托管資源進行回收。

Finalization List和Freachable queue是垃圾回收器內(nèi)部所維護的兩張表,當對象被加入到托管堆中時,如果它實現(xiàn)了Finalize方法,垃圾回收器會在它的Finalization List中加入一個指向該對象的指針。假設A~J是在托管堆中所建立的十個對象,在CEFIJ被創(chuàng)建時,系統(tǒng)會檢測到這些對象的類型定義了Finalize方法,就會把這些對象的指針添加到Finalization List中。Finalization List的這些指針分別指向托管堆中帶有終結器的各個對象(見圖3)。這實際上告訴GC,在回收這些對象的內(nèi)存之前,要首先調(diào)用它們的Finalize方法。

隨著程序運行,BEGHIJ成為了垃圾,這時托管堆的第0代已滿,進行垃圾回收,BGH相繼被釋放,內(nèi)存壓縮。而EIJ也是垃圾沒有被釋放,因為Finalization List中存在對EIJ的引用,所以EIJ不能被釋放,這時它就會被放到Freachable queue中,接著還會對它進行引用。CLR中有一個高優(yōu)先級的線程,專門用來調(diào)用Finalize方法。當Freachable queue為空時,該線程為睡眠狀態(tài);當Freachable queue有條目時,該線程將會被喚醒,將會執(zhí)行該列表中每個對象的Finalize方法,并把列表清空,并清除對象引用的指針。直到這時,EIJ才真正成為垃圾。等到下一次垃圾回收時,這幾個對象才有可能被釋放掉(見圖4)。

從上面特殊線程的喚醒方式我們能夠得知,該線程的執(zhí)行時機是不確定的,所以我們不能在該線程工作的時候,來訪問線程數(shù)據(jù)。

實現(xiàn)Finalize方法或析構函數(shù)對性能可能會有負面影響,因此應避免不必要地使用它們。用Finalize方法回收對象使用的內(nèi)存需要至少兩次垃圾回收。當垃圾回收器執(zhí)行回收時,它只回收沒有終結器的不可訪問對象的內(nèi)存。

3.3 釋放模式

在實際開發(fā)中,經(jīng)常要使用到本地資源和非托管資源的類型,比如文件、網(wǎng)絡連接、套接字、互斥體等。一方面,使用終結器會降低系統(tǒng)的性能;另一方面,在使用這些對象的時候,又必須使用它的終結器。CLR不能自動釋放這些內(nèi)存,要手動寫代碼。微軟提供了一種釋放模式:IDisposable接口,里面只有一個Dispose()方法。圖5為釋放模式的基本思路。

一個類提供了釋放模式,它提供了兩種方法去釋放非托管資源。一是手動釋放,即在程序中必須顯示地通過Dispose()方法或Close()方法去釋放它們。二是自動釋放,比如忘記顯示地釋放這些非托管資源,而程序就會自動調(diào)用這個類的終結器去釋放非托管資源。這樣使得程序出錯的可能性降到了最低。而最關鍵的一點是,Dispose()方法的實現(xiàn),它可以阻止Finalize()方法的調(diào)用。也就是說釋放模式的實現(xiàn),即釋放了非托管資源,也加快了程序的運行速度。實現(xiàn)方法見圖6。

另外值得一提的是Finalize()方法應該在較短的時間內(nèi)完成,因為垃圾回收器給Finalize()方法限定了一個時間,如果Finalize()方法在規(guī)定時間內(nèi)還沒有完成,垃圾回收器會終止運行Finalize()方法的線程。下面這些情況下程序會調(diào)用對象的Finalize()方法:

1) 第0代垃圾回收器已滿;

2) 程序調(diào)用了執(zhí)行垃圾回收(GC的Collect)的方法;

3) Windows報告內(nèi)存不足;

4) CLR正在卸載一個應用程序域;

5) CLR正在被卸載。

4 垃圾回收的幾個誤區(qū)

4.1 萬物皆可被回收

GC針對的僅僅是托管資源,對于非托管資源,GC不負責、也無法對其回收。CLR無法識別這些非托管資源的正確類型,無法知道該如何對資源進行釋放。而對于托管資源、元數(shù)據(jù)則給CLR提供了正確的對象引用信息以及釋放資源的方法,這是GC算法的一個重要依據(jù)。

4.2 手動回收可提高性能

GC.Collect();代碼的目的是手動清理內(nèi)存,提高程序的運行效率。但絕大多數(shù)情況下,我們的代碼會變慢,或者根本無法使用。因為GC在Collect的時候,會掛起當前正在運行的所有線程。GC會對第0、1、2代的所有對象進行回收,這是一個非常耗時的工作。

4.3 Finalize會快速并準確地回收對象

對于非托管資源,我們才需要對其進行手動回收處理。而對于托管資源:Finalize的被調(diào)用,是我們不能控制的,是由CLR決定的。重寫了Finalize方法的對象,CLR會額外建立一個鏈表來對其進行維護,用此方法回收對象使用的內(nèi)存需要至少兩次垃圾回收。

5 結束語

綜上所述,.NET的垃圾回收機制非常先進,垃圾收集器使用戶內(nèi)存管理自動化,但也存在著內(nèi)存泄漏和訪問沖突問題。討論這些機制,對我們以后寫出高性能的應用程序有著非常重要的意義。作為一個嚴肅的程序員,我們應該對垃圾回收機制有所了解,這樣有助于我們編寫性能更好的程序代碼。

參考文獻:

[1] 陳廣.C#程序設計基礎教程與實訓[M].北京:北京大學出版社,2005.

[2] 維恩霍爾特..NET性能優(yōu)化[M]. 北京:清華大學出版社,2008.

[3] 編譯/程化..NET垃圾收集器的過去現(xiàn)在和未來(上)[J].程序員.2008(2):16-19.

[4] 編譯/程化..NET垃圾收集器的過去現(xiàn)在和未來(下)[J].程序員.2008(3):14-17.

[5] 白紙人生blogs.http://www.cppblog.com/andxie99/archive/2007/03/24/20538.aspx[EB/OL].

主站蜘蛛池模板: 97在线国产视频| jizz在线观看| 日本高清在线看免费观看| 狠狠亚洲婷婷综合色香| 欧美精品色视频| 理论片一区| 色妺妺在线视频喷水| 亚洲一区二区成人| 二级特黄绝大片免费视频大片 | 国产在线观看一区精品| 日韩成人在线网站| 欧美午夜精品| 国产精品人人做人人爽人人添| 亚洲欧美另类色图| 国产精品第| 99精品视频在线观看免费播放| 国产一区二区影院| 成人久久精品一区二区三区| 精品伊人久久久香线蕉| 在线播放精品一区二区啪视频| 中文字幕在线看| 国产精品无码AⅤ在线观看播放| 日本精品视频一区二区 | 一级全黄毛片| 午夜免费视频网站| 亚洲天堂日韩在线| 亚洲欧美激情小说另类| 欧美中文字幕第一页线路一| 91久久夜色精品| 97国产一区二区精品久久呦| 欧美有码在线| 欧美一区二区福利视频| 欧美在线一级片| 午夜福利在线观看成人| 亚洲综合极品香蕉久久网| 亚洲欧美日韩中文字幕在线一区| 国产网站免费观看| 亚洲男人的天堂网| 毛片在线播放a| 亚洲第一区欧美国产综合| 亚洲 日韩 激情 无码 中出| 97超爽成人免费视频在线播放| 波多野结衣一区二区三区AV| 自慰网址在线观看| 亚洲无码视频一区二区三区| 亚洲Va中文字幕久久一区| 国产精品永久不卡免费视频| 少妇精品网站| 一级片免费网站| 91久久偷偷做嫩草影院电| 91久久精品国产| 久草视频一区| 国产va免费精品| 亚洲一区国色天香| 国产精品七七在线播放| 亚洲天堂自拍| 天堂亚洲网| 97视频精品全国在线观看| 亚洲一区二区三区香蕉| 91九色国产在线| 97se综合| 精品人妻一区二区三区蜜桃AⅤ | 2020精品极品国产色在线观看| 亚洲激情99| 国产精品99在线观看| 免费观看无遮挡www的小视频| 91国内在线观看| 视频二区国产精品职场同事| 91在线播放国产| 国产精品无码翘臀在线看纯欲| 一级毛片无毒不卡直接观看| 久久久久夜色精品波多野结衣| 免费无码AV片在线观看国产| 国产午夜精品一区二区三| 亚洲人成人伊人成综合网无码| 亚洲中文无码av永久伊人| 青青青国产视频| 亚洲中文字幕在线观看| 2020国产精品视频| 国产精品人人做人人爽人人添| 日韩av电影一区二区三区四区 | 亚洲无卡视频|