日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【转】.net框架读书笔记---CLR内存管理\垃圾收集(二)

發(fā)布時(shí)間:2023/12/10 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】.net框架读书笔记---CLR内存管理\垃圾收集(二) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  前幾天學(xué)習(xí)了CLR垃圾收集原理和基本算法,但是那些是僅僅相對(duì)于托管堆而言的,任何非托管資源的類(lèi)型,例如文件、網(wǎng)絡(luò)資源等,都必須支持一種稱(chēng)為終止化(finalization)的操作。

終止化

終止化操作允許一種資源在他所占的內(nèi)存被回收之前首先執(zhí)行一些清理工作。要提供終止化操作操作,必須為類(lèi)型實(shí)現(xiàn)一個(gè)名為Finalize的方法。當(dāng)垃圾收集器判定一個(gè)對(duì)象為可收集的垃圾時(shí),它便會(huì)調(diào)用該對(duì)象的Finalize方法(如果存在的話(huà))。

  C#為定義Finalize方法提供了特殊的語(yǔ)法看下面代碼;

public?class?OSHandler
{
private?IntPtr handler;

public?OSHandler(IntPtr handler)
{
handler?=?handler;
}

//?當(dāng)垃圾收集器執(zhí)行時(shí),該析構(gòu)函數(shù)將被調(diào)用,它將關(guān)閉非托管資源句柄
~?OSHandler()
{
CloseHandler(handler);
}

public?IntPtr ToHandler()
{
return?handler;
}

//?釋放非托管資源
[System.Runtime.InteropServices.DllImport(?"?Kernel32?"?)]
private?extern?static?bool?CloseHandler(IntPtr handler);
}

查看中間語(yǔ)言

.method family hidebysig?virtual?instance?void
Finalize() cil managed
{
//?代碼大小 26 (0x1a)
.maxstack?1
.?try
{
IL_0000: nop
IL_0001: ldarg.?0
IL_0002: ldfld native?int?FinalizeStudy.OSHandler::?'?handler?'
IL_0007: call?bool?FinalizeStudy.OSHandler::CloseHandler(native?int?)
IL_000c: pop
IL_000d: nop
IL_000e: leave.s IL_0018
}?//?end .try
finally
{
IL_0010: ldarg.?0
IL_0011: call instance?void?[mscorlib]System.Object::Finalize()
IL_0016: nop
IL_0017: endfinally
}?//?end handler
IL_0018: nop
IL_0019: ret
}?//?end of method OSHandler::Finalize

?

會(huì)發(fā)現(xiàn),析構(gòu)函數(shù)被編譯器編譯為Finalize函數(shù),并且使用了異常處理。

  這樣當(dāng)未來(lái)某個(gè)時(shí)刻垃圾收集器判定對(duì)象為可收集的垃圾時(shí),它會(huì)看到該類(lèi)型定義有一個(gè)Finalize方法,于是它便會(huì)調(diào)用該方法,從而允許CLoseHandler函數(shù)來(lái)關(guān)閉其中的非托管資源。在Finalize方法返回之后的某個(gè)時(shí)刻,該OSHandler對(duì)象在托管堆中所占的內(nèi)存才會(huì)被回收。

  應(yīng)該避免使用Finalize方法。有以下原因:

  • 實(shí)現(xiàn)了Finalize的對(duì)象其代齡會(huì)被提高,增加內(nèi)存的壓力,甚至被該對(duì)象直接或者間接引用的對(duì)象的代齡也將被提升(以后學(xué)習(xí)代齡)。
  • 終止化對(duì)象的分配花費(fèi)的時(shí)間較長(zhǎng),因?yàn)橹赶蛩鼈兊闹羔槺仨毐环旁诮K止化鏈表上;
  • 強(qiáng)制垃圾收集器執(zhí)行Finalize方法會(huì)極大的損失程序的性能;
  • 不能控制Finalize方法何時(shí)執(zhí)行。對(duì)象可能會(huì)一直占有著資源,直到出現(xiàn)垃圾收集;
  • CLR不對(duì)Finalize方法的執(zhí)行順序做任何的保障。加入對(duì)象包含指向另一個(gè)對(duì)象的指針,兩個(gè)對(duì)象都可能會(huì)被垃圾收集,順序的不一樣會(huì)導(dǎo)致結(jié)果不可預(yù)期。靠,個(gè)人感覺(jué)這就是一個(gè)bug。

終止化操作的內(nèi)部機(jī)理

  創(chuàng)建一個(gè)新對(duì)象,new先為對(duì)象在托管堆上面分配內(nèi)存。如果對(duì)象的類(lèi)型定義了FInalize方法,那么在該類(lèi)型的實(shí)例被調(diào)用之前,指向該對(duì)象的一個(gè)指針將被放到一個(gè)稱(chēng)為終止化鏈表(finalization list)的數(shù)據(jù)結(jié)構(gòu)里面。終止化鏈表是一個(gè)由垃圾收集器控制的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。鏈表上的每一個(gè)條目都引用著一個(gè)對(duì)象。這實(shí)際告訴垃圾收集器在回收這些對(duì)象的內(nèi)存之前要首先調(diào)用它們的Finalize方法。

  當(dāng)垃圾收集檢測(cè)到可收集的垃圾時(shí),垃圾收集器會(huì)掃描終止化鏈表是否有執(zhí)行可收集垃圾的對(duì)象,當(dāng)找到這樣的指針,它們會(huì)從終止化鏈表移除,并添加到一個(gè)稱(chēng)為終止化可達(dá)列表(freachable queue)的數(shù)據(jù)結(jié)構(gòu)上。在終止化可達(dá)列表上出現(xiàn)的對(duì)象表示該對(duì)象的Finalize方法即將被調(diào)用,當(dāng)垃圾收集完畢后,沒(méi)有Finalize的對(duì)象的內(nèi)存將被回收,實(shí)現(xiàn)了Finalize的對(duì)象內(nèi)存卻不能被回收,因?yàn)樗麄兊腇inalize方法還沒(méi)有被調(diào)用。CLR有一個(gè)特殊的高優(yōu)先級(jí)的線(xiàn)程用來(lái)專(zhuān)門(mén)調(diào)用Finalize方法。該線(xiàn)程可以避免線(xiàn)程同步問(wèn)題。

  非常有意義的是,當(dāng)垃圾收集器將一個(gè)對(duì)象從終止化鏈表轉(zhuǎn)移到終止化可達(dá)隊(duì)列時(shí),該對(duì)象不再認(rèn)為是可收集的垃圾對(duì)象,它的內(nèi)存也就不可能被回收。到此為止,垃圾收集器完成了垃圾對(duì)象的鑒別工作,一些原先認(rèn)為是垃圾的對(duì)象現(xiàn)在被認(rèn)為不是垃圾,從某種意義上來(lái)說(shuō),對(duì)象又“復(fù)蘇”了。當(dāng)?shù)谝淮卫占瘓?zhí)行完畢后,特殊的CLR線(xiàn)程將會(huì)清空終止化可達(dá)隊(duì)列中的對(duì)象,同時(shí)執(zhí)行其中某個(gè)對(duì)象的Finalize方法。

  等下一次垃圾收集執(zhí)行的時(shí)候,它會(huì)看到這些終止化對(duì)象已經(jīng)成為真正的垃圾對(duì)象,這樣實(shí)現(xiàn)了Finalize的對(duì)象的內(nèi)存才被完全回收。 實(shí)際上終止化對(duì)象需要執(zhí)行兩次垃圾收集才能釋放它所占用的內(nèi)存。實(shí)際上由于代齡的提高,可能收集次數(shù)會(huì)多于兩次。上面這些玩意在Effective C#里面也講過(guò),以前沒(méi)有看懂。

?

Dispose模式

  感覺(jué)CLR的終止化是個(gè)吃力不討好的玩意

  • 分配起來(lái)慢(加入終止化鏈表),
  • 收集起來(lái)更慢,先是加入可達(dá)終止化列表,讓對(duì)象復(fù)活,二次垃圾回收才能收集;
  • 不能人為的控制,長(zhǎng)時(shí)間占用內(nèi)存;
  • 增加對(duì)象的代齡,更是不可饒恕。
  • 怎么辦??

  微軟總是NB的,作者總是掉人胃口的,CLR提供了顯式釋放或者關(guān)閉對(duì)象的能力,但是類(lèi)型需要實(shí)現(xiàn)一種被稱(chēng)為Dispose的模式(當(dāng)然有一些約定)。如果一個(gè)類(lèi)型實(shí)現(xiàn)了Dispose模式,使用該類(lèi)型的開(kāi)發(fā)人員將能夠知道當(dāng)對(duì)象不再被使用時(shí)如何顯式地釋放掉它所占用的資源。

   新版本的OSHandler實(shí)現(xiàn),應(yīng)用了Dispose接口:

public?class?OSHandler:IDisposable
{
private?IntPtr handler;

public?OSHandler(IntPtr handler)
{
this?.handler?=?handler;
}

//?當(dāng)垃圾收集器執(zhí)行時(shí),該析構(gòu)函數(shù)將被調(diào)用,它將關(guān)閉非托管資源句柄
~?OSHandler()
{
Dispose(?false?);
}

public?IntPtr ToHandler()
{
return?handler;
}

//?釋放非托管資源
[System.Runtime.InteropServices.DllImport(?"?Kernel32?"?)]
private?extern?static?bool?CloseHandler(IntPtr handler);


public?void?Dispose()
{
//?因?yàn)閷?duì)象的資源被顯示清理,所以在這里阻止垃圾收集器調(diào)用Finalize方法
GC.SuppressFinalize(?this?);
//?進(jìn)行實(shí)際清理工作
Dispose(?true?);

}

//?可以替換Dispose方法
public?void?Close()
{
Dispose();
}

//?執(zhí)行清理工作,protected為了子類(lèi)
protected?void?Dispose(?bool?disposing)
{
//?線(xiàn)程安全
lock?(?this?)
{
if?(disposing)
{
//?對(duì)象正在被被顯式關(guān)閉,此時(shí)可以引用其他對(duì)象,因?yàn)镕inalize方法還沒(méi)有被執(zhí)行
}
}
if?(IsValid)
{
//?如果handler有效,那么關(guān)閉之
CloseHandler(handler);

handler?=?InvalidHandler;?//?置為無(wú)效,防止多次調(diào)用
}
}
//?返回一個(gè)無(wú)效的句柄值
public?IntPtr InvalidHandler{?get?{?return?IntPtr.Zero;}}

//?判斷句柄是否有效
public?bool?IsValid {?get?{?return?handler?!=?InvalidHandler; } }
}

  調(diào)用上面的Dispose或者Close方法只是顯式釋放非托管資源,并不會(huì)釋放托管堆中占用的內(nèi)存,釋放對(duì)象內(nèi)存的工作仍然由垃圾收集器負(fù)責(zé),當(dāng)然釋放時(shí)間仍然是不確定的。 

  上面的代碼中Finalize中Dispose方法的disposing參數(shù)被設(shè)為fasle。這將告訴Dispose方法不應(yīng)該執(zhí)行任何其他對(duì)象的代碼。在Close和無(wú)參Dispose方法中disposing參數(shù)為true,因?yàn)槭鞘謩?dòng)執(zhí)行,程序邏輯可以控制,可以在if中執(zhí)行代碼。調(diào)用SuppressFinalize主要是為了避免終止化對(duì)象給垃圾收集器帶來(lái)負(fù)擔(dān)。

  既然已經(jīng)有了手動(dòng)關(guān)閉的方法,為什么還要實(shí)現(xiàn)Finalize方法呢,因?yàn)槲覀儾荒鼙WC程序的使用者一定會(huì)調(diào)用Dispose方法或者Close方法,如果不調(diào)用將會(huì)造成資源浪費(fèi),甚至系統(tǒng)崩潰,但是這不是使用者的錯(cuò)誤,我們的程序應(yīng)該考慮到這一點(diǎn),實(shí)現(xiàn)Finalize就是為了防止這種情況出現(xiàn),作為一個(gè)后備吧。

總結(jié)

以上是生活随笔為你收集整理的【转】.net框架读书笔记---CLR内存管理\垃圾收集(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。