計(jì)算機(jī) 資源管理 外文翻譯 外文文獻(xiàn) 英文文獻(xiàn) Effective C# 中文版改善C程序的50種方法第二章.NET_第1頁
計(jì)算機(jī) 資源管理 外文翻譯 外文文獻(xiàn) 英文文獻(xiàn) Effective C# 中文版改善C程序的50種方法第二章.NET_第2頁
計(jì)算機(jī) 資源管理 外文翻譯 外文文獻(xiàn) 英文文獻(xiàn) Effective C# 中文版改善C程序的50種方法第二章.NET_第3頁
計(jì)算機(jī) 資源管理 外文翻譯 外文文獻(xiàn) 英文文獻(xiàn) Effective C# 中文版改善C程序的50種方法第二章.NET_第4頁
計(jì)算機(jī) 資源管理 外文翻譯 外文文獻(xiàn) 英文文獻(xiàn) Effective C# 中文版改善C程序的50種方法第二章.NET_第5頁
已閱讀5頁,還剩14頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、武漢科技大學(xué)本科畢業(yè)論文外文翻譯.net resource managementbill wagnereffective c#: 50 specific ways to improve your c#,chapter 2,.net resource management,bill wagner,addison wesley professional,2004,77115.net 資源管理比爾·瓦格拉effective c# 中文版改善c#程序的50種方法,第二章,.net 資源管理,比爾·瓦格拉,2004,77115一個(gè)簡單的事實(shí):.net應(yīng)用程序是在一

2、個(gè)托管的環(huán)境里運(yùn)行的,這個(gè)環(huán)境和不同的設(shè)計(jì)器有很大的沖突,這就才有了effective c#。極大限度上的討論這個(gè)環(huán)境的好處,須要把你對(duì)本地化環(huán)境的想法改變?yōu)?net clr。也就意味著要明白.net的垃圾回收器。在你明白這一章里所推薦的內(nèi)容時(shí),有必要對(duì).net的內(nèi)存管理環(huán)境有個(gè)大概的了解。那我們就開始大概的了解一下吧。垃圾回收器(gc)為你控制托管內(nèi)存。不像本地運(yùn)行環(huán)境,你不用負(fù)責(zé)對(duì)內(nèi)存泄漏,不定指針,未初始化指針,或者一個(gè)其它內(nèi)存管理的服務(wù)問題。但垃圾回收器前不是一個(gè)神話:你一樣要自己清理。你要對(duì)非托管資源負(fù)責(zé),例如文件句柄,數(shù)據(jù)鏈接,gdi+對(duì)象,com對(duì)象,以及其它一些系統(tǒng)對(duì)象。這有一

3、個(gè)好消息:因?yàn)間c管理內(nèi)存,明確的設(shè)計(jì)風(fēng)格可以更容易的實(shí)現(xiàn)。循環(huán)引用,不管是簡單關(guān)系還是復(fù)雜的網(wǎng)頁對(duì)象,都非常容易。gc的標(biāo)記以及嚴(yán)謹(jǐn)?shù)母咝惴梢詸z測(cè)到這些關(guān)系,并且完全的刪除不可達(dá)的網(wǎng)頁對(duì)象。gc是通過對(duì)從應(yīng)用程序的根對(duì)象開始,通過樹形結(jié)構(gòu)的“漫游”來斷定一個(gè)對(duì)象是否可達(dá)的,而不是強(qiáng)迫每個(gè)對(duì)象都保持一些引用跟蹤,com就是這樣的。dataset就是一個(gè)很好的例子,展示了這樣的算法是如何簡化并決定對(duì)象的所屬關(guān)系的。dataset是一個(gè)datatable的集合,而每一個(gè)datatable又是datarow的集合,每一個(gè)datarow又是dataitem的集合,datacolum定義了這些類型的

4、關(guān)系。這里就有一些從dataitem到它的列的引用。而同時(shí),datatime也同樣有一個(gè)引用到它的容器上,也就是datarow。datarow包含引用到datatable,最后每個(gè)對(duì)象都包含一個(gè)引用到dataset。如果這還不夠復(fù)雜,那可以創(chuàng)建一個(gè)dataview,它提供對(duì)經(jīng)過過濾后的數(shù)據(jù)表的順序訪問。這些都是由dataviewmanager管理的。所有這些貫穿網(wǎng)頁的引用構(gòu)成了dataset。釋放內(nèi)存是gc的責(zé)任。因?yàn)?net框架的設(shè)計(jì)者讓你不必釋放這些對(duì)象,這些復(fù)雜的網(wǎng)頁對(duì)象引用不會(huì)造成問題。沒有必須關(guān)心這些網(wǎng)頁對(duì)象的合適的釋放順序,這是gc的工作。gc的設(shè)計(jì)結(jié)構(gòu)可以簡化這些問題,它可以識(shí)別

5、這些網(wǎng)頁對(duì)象就是垃圾。在應(yīng)用程序結(jié)束了對(duì)dataset的引用后,沒有人可以引用到它的子對(duì)象了(譯注:就是dataset里的對(duì)象再也引用不到了)。因此,網(wǎng)頁里還有沒有對(duì)象循環(huán)引用dataset,datatables已經(jīng)一點(diǎn)也不重要了,因?yàn)檫@些對(duì)象在應(yīng)用程序都已經(jīng)不能被訪問到了,它們是垃圾了。垃圾回收器在它獨(dú)立的線程上運(yùn)行,用來從你的程序里移除不使用的內(nèi)存。而且在每次運(yùn)行時(shí),它還會(huì)壓縮托管堆。壓縮堆就是把托管堆中活動(dòng)的對(duì)象移到一起,這樣就可以空出連續(xù)的內(nèi)存。圖2.1展示了兩個(gè)沒有進(jìn)行垃圾回收時(shí)的內(nèi)存快照。所有的空閑內(nèi)存會(huì)在垃圾回收進(jìn)行后連續(xù)起來。圖2.1 垃圾回收器不僅僅是移動(dòng)不使用的內(nèi)存,還移除

6、動(dòng)其它的對(duì)象,從而壓縮使用的內(nèi)存,讓出最多的空閑內(nèi)存。 正如你剛開始了解的,垃圾回收器的全部責(zé)任就是內(nèi)存管理。但,所有的系統(tǒng)資源都是你自己負(fù)責(zé)的。你可以通過給自己的類型定義一個(gè)析構(gòu)函數(shù),來保證釋放一些系統(tǒng)資源。析構(gòu)函數(shù)是在垃圾回收器把對(duì)象從內(nèi)存移除前,由系統(tǒng)調(diào)用的。你可以,也必須這樣來釋放任何你所占用的非托管資源。對(duì)象的析構(gòu)函數(shù)有時(shí)是在對(duì)象成為垃圾之后調(diào)用的,但是在內(nèi)存歸還之前。這個(gè)非確定的析構(gòu)函數(shù)意味著在你無法控制對(duì)象析構(gòu)與停止使用之間的關(guān)系(譯注:對(duì)象的析構(gòu)與對(duì)象的無法引用是兩個(gè)完全不同的概念。關(guān)于gc,本人推薦讀者參考一下jeffrey的".net框架程序設(shè)計(jì)(修訂版)&quo

7、t;中討論的垃圾回收器)。對(duì)c+來說這是個(gè)重大的改變,并且這在設(shè)計(jì)上有一個(gè)重大的分歧。有經(jīng)驗(yàn)的c+程序員寫的類總在構(gòu)造函數(shù)內(nèi)申請(qǐng)內(nèi)存并且在析構(gòu)函數(shù)中釋放它們:/ 好的 c+, 壞的c#:class criticalsectionpublic:  / 構(gòu)造系統(tǒng)需要的資源  criticalsection( )  entercriticalsection( );    / 銷毀資源  criticalsection( )  exitcriticalsection( );  ;/ 使用:void func( ) 

8、; / 系統(tǒng)資源的生存周期  criticalsection s;  / do work.  /.  / compiler generates call to destructor.  / code exits critical section.這是一種很常見的c+風(fēng)格,它保證資源無異常的釋放。但這在c#里不工作,至少,與這不同。明確的析構(gòu)函數(shù)不是.net環(huán)境或者c#的一部份。強(qiáng)行用c+的風(fēng)格在c#里使用析構(gòu)函數(shù)不會(huì)讓它正常的工作。在c#里,析構(gòu)函數(shù)確實(shí)是正確的運(yùn)行了,但它不是即時(shí)運(yùn)行的。在前面那個(gè)例子里,代碼最終在critical secti

9、on上,但在c#里,當(dāng)析構(gòu)函數(shù)存在時(shí),它并不是在critical section上。它會(huì)在后面的某個(gè)未知時(shí)間上運(yùn)行。你不知道是什么時(shí)候,你也無法知道是什么時(shí)候。依懶于析構(gòu)函數(shù)同樣會(huì)導(dǎo)致性能上的損失。須要析構(gòu)的對(duì)象在垃圾回收器上放置了一劑性能毒藥。當(dāng)gc發(fā)現(xiàn)某個(gè)對(duì)象是垃圾但是須要析構(gòu)時(shí),它還不能直接從內(nèi)存上刪除這個(gè)對(duì)象。首先,它要調(diào)用析構(gòu)函數(shù),但析構(gòu)函數(shù)的調(diào)用不是在垃圾回收器的同一個(gè)線程上運(yùn)行的。取而代之的是,gc不得不把對(duì)象放置到析構(gòu)隊(duì)列中,讓另一個(gè)線程讓執(zhí)行所有的析構(gòu)函數(shù)。gc繼續(xù)它自己的工作,從內(nèi)存上移除其它的垃圾。在下一個(gè)gc回收時(shí),那些被析構(gòu)了的對(duì)象才會(huì)再從內(nèi)存上移除。圖2.2展示了三

10、個(gè)內(nèi)存使用不同的gc情況。注意,那些須要析構(gòu)的對(duì)象會(huì)待在內(nèi)存里,直到下一次gc回收。圖2.2 這個(gè)順序展示了析構(gòu)函數(shù)在垃圾回收器上起的作用。對(duì)象會(huì)在內(nèi)存里存在的時(shí)間更長,須要啟動(dòng)另一個(gè)線程來運(yùn)行垃圾回收器。這用使你相信:那些須要析構(gòu)的對(duì)象在內(nèi)存至少多生存一個(gè)gc回收循環(huán)。但,我是簡化了這些事。實(shí)際上,因?yàn)榱硪粋€(gè)gc的介入(譯注:其實(shí)只有一個(gè)gc,作者是想引用回收代的問題。),使得情況比這復(fù)雜得多。.net回收器采用”代“來優(yōu)化這個(gè)問題。代可以幫助gc來很快的標(biāo)識(shí)那些看上去看是垃圾的對(duì)象。所以從上一次回后開始創(chuàng)建的對(duì)象稱為第0代對(duì)象,所有那些經(jīng)過一次gc回收后還存在的對(duì)象稱為第1代對(duì)象。所有那些

11、經(jīng)過2次或者2次以上gc回收后還存在的對(duì)象稱為第2代對(duì)象。分代的目的就是用來區(qū)分臨時(shí)變量以及一些應(yīng)用程序的全局變量。第0代對(duì)象很可能是臨時(shí)的變量。成員變量,以及一些全局變量很快會(huì)成為第1代對(duì)象,最終成為第2代對(duì)象。gc通過限制檢測(cè)第1以及第2代對(duì)象來優(yōu)化它的工作。每個(gè)gc循環(huán)都檢測(cè)第0代對(duì)象。粗略假設(shè)個(gè)gc會(huì)超過10次檢測(cè)來檢測(cè)第0代對(duì)象,而要超過100次來檢測(cè)所有對(duì)象。再次考慮析構(gòu)函數(shù)的開銷:一個(gè)須要析構(gòu)函數(shù)的對(duì)象可能要比一個(gè)不用析構(gòu)函數(shù)的對(duì)象在內(nèi)存里多待上9個(gè)gc回收循環(huán)。如果它還沒有被析構(gòu),它將會(huì)移到第2代對(duì)象。在第2代對(duì)象中,一個(gè)可以生存上100個(gè)gc循環(huán)直到下一個(gè)第2代集合。結(jié)束時(shí),

12、記得一個(gè)垃圾回收器負(fù)責(zé)內(nèi)存管理的托管環(huán)境的最大好處:內(nèi)存泄漏,其它指針的服務(wù)問題不在是你的問題。非內(nèi)存資源迫使你要使用析構(gòu)函數(shù)來確保清理非內(nèi)存資源。析構(gòu)函數(shù)會(huì)對(duì)你的應(yīng)用程序性能產(chǎn)生一些影響,但你必須使用它們來防止資源泄漏(譯注:請(qǐng)注意理解非內(nèi)存資源是什么,一般是指文件句柄,網(wǎng)絡(luò)資源,或者其它不能在內(nèi)存中存放的資源)。通過實(shí)現(xiàn)idisposable接口來避免析構(gòu)函數(shù)在垃圾回收器上造成的性能損失。接下來的具體的原則將會(huì)幫助你更有效的使用環(huán)境來開發(fā)程序。effective c# 原則12:選擇變量初始化而不是賦值語句一些類經(jīng)常不只一個(gè)構(gòu)造函數(shù)。時(shí)間一長,就難得讓它的成員變量以及構(gòu)造函數(shù)進(jìn)行同步了。最

13、好的確保這樣的事不會(huì)發(fā)生的方法就是:在聲明就是的時(shí)間就直接初始化,而不是在每個(gè)構(gòu)造函數(shù)內(nèi)進(jìn)行賦值。而且你應(yīng)該使用初始化器語法同時(shí)為靜態(tài)的和實(shí)例的變量進(jìn)行初始化。在c#里,當(dāng)你聲明一個(gè)變量時(shí)就自然的構(gòu)造了這個(gè)成員變量。直接賦值:public class myclass  / declare the collection, and initialize it.  private arraylist _coll = new arraylist( );忽略你最終會(huì)給myclass添加多少個(gè)構(gòu)造函數(shù),_coll會(huì)正確的初始化。編譯器會(huì)產(chǎn)生一些代碼,使得在你的任何一個(gè)構(gòu)造函數(shù)調(diào)用前,都

14、會(huì)初始化你聲明的實(shí)例變量。當(dāng)你添加一個(gè)新的構(gòu)造函數(shù)時(shí),_coll就給你初始化了。當(dāng)你添加了一個(gè)新的變量,你不用在所有的構(gòu)造函數(shù)里添加初始化代碼;直接在聲明的地方對(duì)它進(jìn)行初始化就行了。同樣重要的是:如果你沒有明確的聲明任何一個(gè)構(gòu)造函數(shù),編譯會(huì)默認(rèn)的給你添加一個(gè),并且把所有的變量初始化過程都添加到這個(gè)構(gòu)造函數(shù)里。初始化器更像是一個(gè)到構(gòu)造函數(shù)的方便的快捷方法。初始化生成的代碼會(huì)放置在類型的構(gòu)造函數(shù)之前。初始化會(huì)在執(zhí)行類型的基類的構(gòu)造函數(shù)之前被執(zhí)行,并且它們是按你聲明的先后關(guān)系順序執(zhí)行的。使用初始化器是一個(gè)最簡單的方法,在你的類型里來避免使用一些沒有賦值的變量,但這并不是很好。下面三種情況下,你不應(yīng)該

15、使用初始化器語法。首先就是,如果你是初始化一個(gè)對(duì)象為0,或者為null。系統(tǒng)默認(rèn)會(huì)在你任何代碼執(zhí)行前,為所有的內(nèi)容都初始化為0。系統(tǒng)置0的初始化是基于底層的cpu指令,對(duì)整個(gè)內(nèi)存塊設(shè)置。你的任何其它置0的初始化語句是多余的。c#編譯器忠實(shí)的添加額外的指令把內(nèi)存設(shè)置為0。這并沒有錯(cuò),只是效率不高。事實(shí)上,如果是處理值類型數(shù)據(jù),這是很不值的:myvaltype _myval1;  / initialized to 0myvaltype _myval2 = new myvaltype(); / also 0兩條語句都是把變量置為0。第一個(gè)是通過設(shè)置包含_myval1的內(nèi)存來置0;而第二個(gè)是

16、通過il指令initobj,這對(duì)變量_myval2會(huì)產(chǎn)生裝箱與拆箱操作。這很要花一點(diǎn)額外的時(shí)間(參見原則17)。第二個(gè)低效率的是在你為一個(gè)對(duì)象添加兩個(gè)構(gòu)造函數(shù)時(shí)會(huì)產(chǎn)生。你使用初始化器初始化變量,而所有的構(gòu)造函數(shù)也對(duì)這些變量進(jìn)行了初始化。這個(gè)版本的myclass兩個(gè)不同的arraylist對(duì)象在它的構(gòu)造函數(shù)內(nèi):public class myclass  / declare the collection, and initialize it.  private arraylist _coll = new arraylist( );  myclass( ) 

17、    myclass( int size )      _coll = new arraylist( size );  當(dāng)你創(chuàng)建一個(gè)新的myclass對(duì)象時(shí),特別指定集合的大小,你創(chuàng)建了兩個(gè)數(shù)組列表。其中一個(gè)很快成為垃圾對(duì)象。初始化器在所有的構(gòu)造函數(shù)之前會(huì)執(zhí)行,構(gòu)造函數(shù)會(huì)創(chuàng)建第2個(gè)數(shù)組列表。編譯器產(chǎn)生了這個(gè)的一個(gè)版本,當(dāng)然這是你決不會(huì)手動(dòng)寫出來的。public class myclass  / declare the collection, and initialize it.  private arr

18、aylist _coll;  myclass( )      _coll = new arraylist( );    myclass( int size )      _coll = new arraylist( );    _coll = new arraylist( size );  最后一個(gè)原因要把初始化放到構(gòu)造函數(shù)里就是促使異常的捕獲。你不能在初始化器中使用try塊,任何在構(gòu)造時(shí)因成員變量產(chǎn)生的異??赡苎苌綄?duì)象的外面。你無法試圖在你的

19、類里來捕獲它。你應(yīng)該把那些初始化代碼移到構(gòu)造函數(shù)里,這樣你就可以捕獲異常從而保證你的代碼很友好(參見原則45)。變量初始化器是一個(gè)最簡單的方法,在忽略構(gòu)造函數(shù)時(shí)來保證成員變量被正確的初始化。初始化器在所有的構(gòu)造函數(shù)之前被執(zhí)行。使用這樣的語法意味著當(dāng)你在為后來發(fā)布的版本中添加了構(gòu)造函數(shù)時(shí),不會(huì)忘記添加恰當(dāng)?shù)某跏蓟綐?gòu)造函數(shù)里。當(dāng)構(gòu)造函數(shù)與初始化生成同樣的成員對(duì)象時(shí),就使用初始化器。閱讀簡單而且易于維護(hù)。effective c# 原則13:用靜態(tài)構(gòu)造函數(shù)初始化類的靜態(tài)成員你應(yīng)該知道,在一個(gè)類型的任何實(shí)例初始化以前,你應(yīng)該初始化它的靜態(tài)成員變量。在里c#你可以使用靜態(tài)的預(yù)置方法和靜態(tài)構(gòu)造函數(shù)來實(shí)現(xiàn)這

20、個(gè)目的。一個(gè)類的靜態(tài)構(gòu)造函數(shù)是一個(gè)與眾不同的,它在所有的方法,變量或者屬性訪問前被執(zhí)行。你可以用這個(gè)函數(shù)來初始化靜態(tài)成員變量,強(qiáng)制使用單件模式,或者實(shí)現(xiàn)其它任何在類型的實(shí)例可用前應(yīng)該完成的工作。你不能用任何的實(shí)例構(gòu)造函數(shù),其它特殊的私有函數(shù), 或者任何其它習(xí)慣方法來初始化一個(gè)變量。和實(shí)例的預(yù)置方法一樣,你可以把靜態(tài)的預(yù)置方法做為靜態(tài)構(gòu)造函數(shù)可替代的選擇。如果須要簡單的分配一個(gè)靜態(tài)成員,就直接使用初始化語法。當(dāng)你有更復(fù)雜的邏輯來初始化靜態(tài)成員變量時(shí),就創(chuàng)建一個(gè)靜態(tài)構(gòu)造函數(shù):public class mysingleton  private static readonly mysingl

21、eton _theoneandonly =    new mysingleton( );  public static mysingleton theonly      get          return _theoneandonly;        private mysingleton( )      / remainder elided可以用下面的

22、方法簡單的實(shí)現(xiàn)單件模式,實(shí)際上你在初始化一個(gè)單件模式時(shí)可能有更復(fù)雜的邏輯:public class mysingleton  private static readonly mysingleton _theoneandonly;  static mysingleton( )      _theoneandonly = new mysingleton( );    public static mysingleton theonly      get  

23、60;       return _theoneandonly;        private mysingleton( )      / remainder elided同樣,和實(shí)例的預(yù)置方法一樣,靜態(tài)的預(yù)置方法在靜態(tài)的構(gòu)造函數(shù)調(diào)用前執(zhí)行。并且,你的靜態(tài)預(yù)置方法在基類的靜態(tài)構(gòu)造函數(shù)執(zhí)行前被執(zhí)行。當(dāng)應(yīng)用程序第一次裝載你的數(shù)據(jù)類型時(shí),clr自動(dòng)調(diào)用靜態(tài)構(gòu)造函數(shù)。你只能定義一個(gè)靜態(tài)構(gòu)造函數(shù),并且不能有參數(shù)。因?yàn)殪o態(tài)構(gòu)造函數(shù)是clr調(diào)用的,你必須十分注意異常的產(chǎn)生。如果在

24、靜態(tài)構(gòu)造函數(shù)里產(chǎn)生了異常,clr將會(huì)直接終止你的應(yīng)用程序。正因?yàn)楫惓?,靜態(tài)構(gòu)造函數(shù)常常代替靜態(tài)預(yù)置方法。如果你使用靜態(tài)預(yù)置方法,你自己不能捕獲異常。做為一個(gè)靜態(tài)的構(gòu)造,你可以這樣(參見原則45):static mysingleton( )  try     _theoneandonly = new mysingleton( );  catch      / attempt recovery here.  靜態(tài)預(yù)置方法和靜態(tài)構(gòu)造函數(shù)為你的類提供了最清爽的方法來初始化靜態(tài)成員。與其它語言不同,它們被

25、添加到c#語言中,是初始化靜態(tài)成員的兩個(gè)不同的特殊位置。the simple fact that .net programs run in a managed environment has a big impact on the kinds of designs that create effective c#. taking utmost advantage of that environment requires changing your thinking from native environments to the .net clr. it means understanding

26、the .net garbage collector. an overview of the .net memory management environment is necessary to understand the specific recommendations in this chapter, so let's get on with the overview.the garbage collector (gc) controls managed memory for you. unlike native environments, you are not respons

27、ible for memory leaks, dangling pointers, uninitialized pointers, or a host of other memory-management issues. but the garbage collector is not magic: you need to clean up after yourself, too. you are responsible for unmanaged resources such as file handles, database connections, gdi+ objects, com o

28、bjects, and other system objects.here's the good news: because the gc controls memory, certain design idioms are much easier to implement. circular references, both simple relationships and complex webs of objects, are much easier. the gc's mark and compact algorithm efficiently detects thes

29、e relationships and removes unreachable webs of objects in their entirety. the gc determines whether an object is reachable by walking the object tree from the application's root object instead of forcing each object to keep track of references to it, as in com. the dataset class provides an exa

30、mple of how this algorithm simplifies object ownership decisions. a dataset is a collection of datatables. each datatable is a collection of datarows. each datarow is a collection of dataitems. each datatable also contains a collection of datacolumns. datacolumns define the types associated with eac

31、h column of data. there are other references from the dataitems to its appropriate column. every dataitem also contains a reference to its container, the datarow. datarows contain references back to the datatable, and everything contains a reference back to the containing dataset.if that's not c

32、omplicated enough, you can create dataviews that provide access to filtered sequences of a data table. those are all managed by a dataviewmanager. there are references all through the web of objects that make up a dataset. releasing memory is the gc's responsibility. because the .net framework d

33、esigners did not need to free these objects, the complicated web of object references did not pose a problem. no decision needed to be made regarding the proper sequence of freeing this web of objects; it's the gc's job. the gc's design simplifies the problem of identifying this kind of

34、web of objects as garbage. after the application releases its reference to the dataset, none of the subordinate objects can be reached. it does not matter that there are still circular references to the dataset, datatables, and other objects in the web. because these objects cannot be reached from t

35、he application, they are all garbage.the garbage collector runs in its own thread to remove unused memory from your program. it also compacts the managed heap each time it runs. compacting the heap moves each live object in the managed heap so that the free space is located in one contiguous block o

36、f memory. figure 2.1 shows two snapshots of the heap before and after a garbage collection. all free memory is placed in one contiguous block after each gc operation.figure 2.1. the garbage collector not only removes unused memory, but it moves other objects in memory to compact used memory and maxi

37、mize free space.as you've just learned, memory management is completely the responsibility of the garbage collector. all other system resources are your responsibility. you can guarantee that you free other system resources by defining a finalizer in your type. finalizers are called by the syste

38、m before an object that is garbage is removed from memory. you canand mustuse these methods to release any unmanaged resources that an object owns. the finalizer for an object is called at some time after it becomes garbage and before the system reclaims its memory. this nondeterministic finalizatio

39、n means that you cannot control the relationship between when you stop using an object and when its finalizer executes. that is a big change from c+, and it has important ramifications for your designs. experienced c+ programmers wrote classes that allocated a critical resource in its constructor an

40、d released it in its destructor:/ good c+, bad c#:class criticalsectionpublic: / constructor acquires the system resource. criticalsection( ) entercriticalsection( ); / destructor releases system resource. criticalsection( ) exitcriticalsection( ); ;/ usage:void func( ) / the lifetime of s controls

41、access to / the system resource. criticalsection s; / do work. /. / compiler generates call to destructor. / code exits critical section.this common c+ idiom ensures that resource deallocation is exception-proof. this doesn't work in c#, howeverat least, not in the same way. deterministic finali

42、zation is not part of the .net environment or the c# language. trying to force the c+ idiom of deterministic finalization into the c# language won't work well. in c#, the finalizer eventually executes, but it doesn't execute in a timely fashion. in the previous example, the code eventually e

43、xits the critical section, but, in c#, it doesn't exit the critical section when the function exits. that happens at some unknown time later. you don't know when. you can't know when.relying on finalizers also introducesperformance penalties. objects that require finalization put a perfo

44、rmance drag on the garbage collector. when the gc finds that an object is garbage but also requires finalization, it cannot remove that item from memory just yet. first, it calls the finalizer. finalizers are not executed by the same thread that collects garbage. instead, the gc places each object t

45、hat is ready for finalization in a queue and spawns yet another thread to execute all the finalizers. it continues with its business, removing other garbage from memory. on the next gc cycle, those objects that have been finalized are removed from memory. figure 2.2 shows three different gc operatio

46、ns and the difference in memory usage. notice that the objects that require finalizers stay in memory for extra cycles.figure 2.2. this sequence shows the effect of finalizers on the garbage collector. objects stay in memory longer, and an extra thread needs to be spawned to run the garbage collecto

47、r. this might lead you to believe that an object that requires finalization lives in memory for one gc cycle more than necessary. but i simplified things. it's more complicated than that because of another gc design decision. the .net garbage collector defines generations to optimize its work. g

48、enerations help the gc identify the likeliest garbage candidates more quickly. any object created since the last garbage collection operation is a generation 0 object. any object that has survived one gc operation is a generation 1 object. any object that has survived two or more gc operations is a

49、generation 2 object. the purpose of generations is to separate local variables and objects that stay around for the life of the application. generation 0 objects are mostly local variables. member variables and global variables quickly enter generation 1 and eventually enter generation 2.the gc opti

50、mizes its work by limiting how often it examines first- and second-generation objects. every gc cycle examines generation 0 objects. roughly 1 gc out of 10 examines the generation 0 and 1 objects. roughly 1 gc cycle out of 100 examines all objects. think about finalization and its cost again: an obj

51、ect that requires finalization might stay in memory for nine gc cycles more than it would if it did not require finalization. if it still has not been finalized, it moves to generation 2. in generation 2, an object lives for an extra 100 gc cycles until the next generation 2 collection.to close, rem

52、ember that a managed environment, where the garbage collector takes the responsibility for memory management, is a big plus: memory leaks and a host of other pointer-related problems are no longer your problem. nonmemory resources force you to create finalizers to ensure proper cleanup of those nonm

53、emory resources. finalizers can have a serious impact on the performance of your program, but you must write them to avoid resource leaks. implementing and using the idisposable interface avoids the performance drain on the garbage collector that finalizers introduce. the next section moves on to th

54、e specific items that will help you create programs that use this environment more effectively.item 12: prefer variable initializers to assignment statementsclasses often have more than one constructor. over time, it's easy for the member variables and the constructors to get out of synch. the b

55、est way to make sure this doesn't happen is to initialize variables where you declare them instead of in the body of every constructor. you should utilize the initializer syntax for both static and instance variables.constructing member variables when you declare that variable is natural in c#.

56、just assign a value:public class myclass / declare the collection, and initialize it. private arraylist _coll = new arraylist( );regardless of the number of constructors you eventually addto the myclass type, _coll will be initialized properly. the compiler generates code at the beginning of each co

57、nstructor to execute all the initializers you have defined for your instance member variables. when you add a new constructor, _coll gets initialized. similarly, if you add a new member variable, you do not need to add initialization code to every constructor; initializing the variable where you def

58、ine it is sufficient. equally important, the initializers are added to the compiler-generated default constructor. the c# compiler creates a default constructor for your types whenever you don't explicitly define any constructors.initializers are more than a convenient shortcut for statements in

59、 a constructor body. the statements generated by initializers are placed in object code before the body of your constructors. initializers execute before the base class constructor for your type executes, and they are executed in the order the variables are declared in your class.using initializers is the simplest way to avoid uninitialized variables in your types, but it's not perfect. in three cases, you should not use the initializer syntax. the first is when you are initializing the object to 0, or null. the default system initialization sets everyth

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論