溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何深度剖析C++資源管理細(xì)節(jié)

發(fā)布時(shí)間:2021-10-27 18:28:19 來(lái)源:億速云 閱讀:153 作者:柒染 欄目:編程語(yǔ)言

如何深度剖析C++資源管理細(xì)節(jié),很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。

我們從系統(tǒng)結(jié)構(gòu)的角度上講,C/C++ 支持 3 種內(nèi)存管理方式,基于棧的C++資源管理,基于堆的動(dòng)態(tài)管理,和基于全局區(qū)的靜態(tài)管理,僅供大家學(xué)習(xí)切磋。

C++資源管理兩門語(yǔ)言的定位不同,它們?cè)谫Y源管理方面采取了兩種截然不同的方式:一為GC,一為RAII。GC讓程序建立在更高的抽象層次上,使資源管理變得更方便,更安全;而RAII則保留了C的底層能力,同時(shí)在C++特性的支持下提供了簡(jiǎn)單有效的資源管理方式。

我們知道C++最激烈的批評(píng)往往來(lái)自于C社區(qū),而在我看來(lái)C程序員可以不接受虛函數(shù),不接受模板,但有什么理由不接受RAII呢?可以說(shuō)RAII是C++相對(duì)C來(lái)說(shuō)幾乎無(wú)副作用的明顯進(jìn)步。

下面就從GC開(kāi)始:

C#通過(guò)CLR管理托管內(nèi)存,用引用抽象代替指針間接操作托管內(nèi)存,讓程序員在更高的層次上安全地使用資源。這使得C#失去了直接管理內(nèi)存的能力,但換來(lái)了以下好處:

1.類型安全:在C/C++中可以通過(guò)類型轉(zhuǎn)換把整數(shù)或其他類型的指針轉(zhuǎn)換為特定類型的指針,這意味著指針是非類型安全的,必須由程序員來(lái)保證指針代表的內(nèi)存空間的合法性。而C#引用可以看作是類型安全的指針,as運(yùn)算符可以保證轉(zhuǎn)換的類型安全性。

2.內(nèi)存整理:創(chuàng)建對(duì)象需要從堆中動(dòng)態(tài)分配連續(xù)的內(nèi)存空間,由于不同對(duì)象的內(nèi)存大小是不同的,常見(jiàn)的***匹配和***匹配堆分配算法都會(huì)造成堆中的內(nèi)存碎片問(wèn)題。碎片的存在使實(shí)際可用內(nèi)存小于物理內(nèi)存,所以應(yīng)盡量減少碎片的產(chǎn)生。

一個(gè)方向是設(shè)計(jì)更好的內(nèi)存分配算法;另一個(gè)方向是通過(guò)周期性地進(jìn)行內(nèi)存整理調(diào)整優(yōu)化。在C++資源管理中,由于指針代表了絕對(duì)地址,因此不存在通用的內(nèi)存整理算法;而C#屏蔽了指針,通過(guò)引用操作對(duì)象,就使得內(nèi)存整理成為可能。

PS:這并不意味著C/C++內(nèi)存分配就弱于C#,C++資源管理可以為某種類型的對(duì)象設(shè)計(jì)專用的內(nèi)存分配方式,甚至把對(duì)象指定分配到某一物理地址空間,這些都是C#不具備的。

托管和非托管資源

在C#中,資源分為托管資源和非托管資源兩種。GC在回收無(wú)用對(duì)象資源時(shí),可以自動(dòng)回收托管資源(比如托管內(nèi)存),但對(duì)于非托管資源(比如Socket、文件、數(shù)據(jù)庫(kù)連接)必須在程序中顯式釋放。

托管資源的回收首先需要GC識(shí)別無(wú)用對(duì)象,然后回收其資源。一般無(wú)用對(duì)象是指通過(guò)當(dāng)前的系統(tǒng)根對(duì)象和調(diào)用堆棧對(duì)象不可達(dá)的對(duì)象。對(duì)象有一個(gè)重要的特點(diǎn)導(dǎo)致無(wú)用對(duì)象判斷的復(fù)雜性:對(duì)象間的相互引用!如果沒(méi)有相互引用,就可以通過(guò)“引用計(jì)數(shù)”這種簡(jiǎn)單高效的方式實(shí)現(xiàn)無(wú)用對(duì)象的判斷,并實(shí)現(xiàn)實(shí)時(shí)回收。

正是由于相互引用的存在導(dǎo)致GC需要設(shè)計(jì)更為復(fù)雜的算法,這樣帶來(lái)的***問(wèn)題在于喪失了資源回收的實(shí)時(shí)性,而變成一種不確定的方式。對(duì)于非托管資源的釋放,C#提供了兩種方式:

1.Finalizer:寫法貌似C++資源管理的析構(gòu)函數(shù),本質(zhì)上卻相差甚遠(yuǎn)。Finalizer是對(duì)象被GC回收之前調(diào)用的終結(jié)器,初衷是在這里釋放非托管資源,但由于GC運(yùn)行時(shí)機(jī)的不確定性,通常會(huì)導(dǎo)致非托管資源釋放不及時(shí)。

另外,F(xiàn)inalizer可能還會(huì)有意想不到的副作用,比如:被回收的對(duì)象已經(jīng)沒(méi)有被其他可用對(duì)象所引用,但Finalizer內(nèi)部卻把它重新變成可用,這就破壞了GC垃圾收集過(guò)程的原子性,增大了GC開(kāi)銷。

2.Dispose Pattern:C#提供using關(guān)鍵字支持Dispose Pattern進(jìn)行資源釋放。這樣能通過(guò)確定的方式釋放非托管資源,而且using結(jié)構(gòu)提供了異常安全性。所以,一般建議采用Dispose Pattern,并在Finalizer中輔以檢查,如果忘記顯式Dispose對(duì)象則在Finalizer中釋放資源。

可以說(shuō),GC為程序帶來(lái)安全方便的同時(shí)也付出了不小的代價(jià):一則喪失了托管資源回收的實(shí)時(shí)性,這在實(shí)時(shí)系統(tǒng)和資源受限系統(tǒng)中是致命的;二則沒(méi)有把托管資源和非托管資源的管理統(tǒng)一起來(lái),造成概念割裂。

C++的定位之一是底層開(kāi)發(fā)能力,所以不難理解GC并沒(méi)有成為C++的語(yǔ)言特性。雖然我們?cè)?span >C++0x和各種第三方庫(kù)都能看到GC的身影,但GC對(duì)于C++來(lái)講并不是那么重要,至多是一個(gè)有益的補(bǔ)充。C++資源管理足以傲視C,并和C# GC一較高下的是它的RAII。

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI