溫馨提示×

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

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

c#中托管和非托管資源詳解

發(fā)布時(shí)間:2020-07-15 15:38:39 來(lái)源:億速云 閱讀:182 作者:小豬 欄目:開(kāi)發(fā)技術(shù)

小編這次要給大家分享的是c#中托管和非托管資源詳解,文章內(nèi)容豐富,感興趣的小伙伴可以來(lái)了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。

前言

c# 托管和非托管比較重要,因?yàn)檫@涉及到資源的釋放。

現(xiàn)在只要在計(jì)算機(jī)上運(yùn)行的,無(wú)論玩出什么花來(lái),整個(gè)什么概念,逃不過(guò)輸入數(shù)據(jù)修改數(shù)據(jù)輸出數(shù)據(jù)(計(jì)算機(jī)本質(zhì)),這里面有個(gè)數(shù)據(jù)的輸入,那么我們的內(nèi)存有限啊,這里面就牽扯到數(shù)據(jù)釋放。

看下c# 的垃圾回收是怎么樣的。

了解垃圾回收之前首先要了解數(shù)據(jù),了解數(shù)據(jù)需要了解數(shù)據(jù)類(lèi)型啊,數(shù)據(jù)類(lèi)型分為值類(lèi)型還有引用類(lèi)型。

windows 使用一個(gè)虛擬尋址系統(tǒng),該系統(tǒng)把程序可用的內(nèi)存地址映射到硬件內(nèi)存中的實(shí)際地址上,這些任務(wù)完全由windows 在后臺(tái)管理。我們的程序運(yùn)行在操作系統(tǒng)上,那么我們作為程序員關(guān)系的就是這個(gè)虛擬尋址系統(tǒng)。

這東西有什么用呢?

比如32位系統(tǒng)中,每個(gè)進(jìn)程所占用的最多4G(4G這樣來(lái)的,2^32,4個(gè)字節(jié)),那么這個(gè)程序如果進(jìn)行管理的這4G,它不需要知道在硬件地址是多少。

比如這個(gè)進(jìn)程申請(qǐng)了1k內(nèi)存,那么這個(gè)進(jìn)程管理的實(shí)際是從0到1k的虛擬內(nèi)存,而不需要知道這個(gè)硬件物理內(nèi)存地址是多少,有一個(gè)可以直接證明的就是我們寫(xiě)c++輸出指針的時(shí)候,發(fā)現(xiàn)指針輸出1千多,

你覺(jué)得可能是物理內(nèi)存地址的1千多嗎?默默的打開(kāi)資源管理看看現(xiàn)在占用多少內(nèi)存。

默認(rèn)情況下,32 位計(jì)算機(jī)上的每個(gè)進(jìn)程都具有 2 GB 的用戶模式虛擬地址空間。這里解釋一下,每個(gè)進(jìn)程2個(gè)G是虛擬地址,就是在這個(gè)進(jìn)程維護(hù)一個(gè)2G的虛擬地址,并不是實(shí)際占有2G的硬件內(nèi)存地址。

盜一張圖:

c#中托管和非托管資源詳解

虛擬地址有三種狀態(tài):

狀態(tài)描述
Free該內(nèi)存塊沒(méi)有引用關(guān)系,可用于分配。
保留內(nèi)存塊可供你使用,并且不能用于任何其他分配請(qǐng)求。 但是,在該內(nèi)存塊提交之前,你無(wú)法將數(shù)據(jù)存儲(chǔ)到其中。
已提交內(nèi)存塊已指派給物理存儲(chǔ)。

那么這個(gè)虛擬內(nèi)存上又分了堆和棧,棧上存儲(chǔ)值類(lèi)型,堆上存儲(chǔ)引用類(lèi)型。

他們的存儲(chǔ)方式不一樣。

下面是棧:

c#中托管和非托管資源詳解

棧是這樣子的先用高位后用低為,比如申請(qǐng)80000,先用的就是80000 直到為0為止。

{
 int a=10;
 double b=100.0;
}

如上圖,80000用完了,這時(shí)候棧指針指向80000。

現(xiàn)在int a了,int是4個(gè)字節(jié),這時(shí)候棧指針減4,到79996這個(gè)位置。

然后是double,double 為8個(gè)字節(jié),這時(shí)候棧指針減8,以此類(lèi)推。

然后如果變量超出作用域,那么這個(gè)時(shí)候就會(huì)被垃圾回收,棧指針增加8,然后增加4。(記得棧指針增加的時(shí)候[垃圾回收]并不會(huì)去把已經(jīng)使用的地址重置為0,只有類(lèi)型申明的時(shí)候才重置為0,然后再賦值)

下面是引用類(lèi)型:

c#中托管和非托管資源詳解

堆是這樣子的,已用的內(nèi)存地址小,空閑的內(nèi)存地址大。

舉個(gè)栗子:

{
 student a;
 a=new student;
}

首先運(yùn)行student a,這個(gè)時(shí)候存儲(chǔ)的是引用地址,也就是4個(gè)字節(jié),存放在棧上。

然后運(yùn)行a=new student(),首先假設(shè)student使用64個(gè)字節(jié),那么在堆上就申請(qǐng)連續(xù)的64個(gè)字節(jié),然后把首地址傳遞賦值給a。

上面非常大的程度簡(jiǎn)化了程序的內(nèi)存分配,引用類(lèi)型垃圾回收的一個(gè)簡(jiǎn)化版就是——當(dāng)一個(gè)引用變量超出作用域的時(shí)候,它會(huì)從棧中刪除,但是引用對(duì)象的數(shù)據(jù)保存在堆中,只有沒(méi)有任何一個(gè)引用變量指向引用對(duì)象的時(shí)候那么這個(gè)引用對(duì)象才會(huì)回收。

好的,知道了數(shù)據(jù)存儲(chǔ)是怎么樣的,來(lái)看一下垃圾回收吧。

正文

關(guān)于垃圾回收,.net 文檔是這樣介紹的。

.NET 的垃圾回收器管理應(yīng)用程序的內(nèi)存分配和釋放。
每當(dāng)有對(duì)象新建時(shí),公共語(yǔ)言運(yùn)行時(shí)都會(huì)從托管堆為對(duì)象分配內(nèi)存。
只要托管堆中有地址空間,運(yùn)行時(shí)就會(huì)繼續(xù)為新對(duì)象分配空間。
不過(guò),內(nèi)存并不是無(wú)限的。 垃圾回收器最終必須執(zhí)行垃圾回收來(lái)釋放一些內(nèi)存。
垃圾回收器的優(yōu)化引擎會(huì)根據(jù)所執(zhí)行的分配來(lái)確定執(zhí)行回收的最佳時(shí)機(jī)。
執(zhí)行回收時(shí),垃圾回收器會(huì)在托管堆中檢查應(yīng)用程序不再使用的對(duì)象,然后執(zhí)行必要的操作來(lái)回收其內(nèi)存。

那么什么時(shí)候垃圾回收呢?

1.系統(tǒng)具有低的物理內(nèi)存。 這是通過(guò) OS 的內(nèi)存不足通知或主機(jī)指示的內(nèi)存不足檢測(cè)出來(lái)。

2.由托管堆上已分配的對(duì)象使用的內(nèi)存超出了可接受的閾值。 隨著進(jìn)程的運(yùn)行,此閾值會(huì)不斷地進(jìn)行調(diào)整。

3.調(diào)用 GC.Collect 方法。 幾乎在所有情況下,你都不必調(diào)用此方法,因?yàn)槔厥掌鲿?huì)持續(xù)運(yùn)行。 此方法主要用于特殊情況和測(cè)試。

第三個(gè).net 平臺(tái)會(huì)幫我們處理,第二個(gè)托管堆會(huì)幫我們自我調(diào)整,關(guān)鍵是第1個(gè)如何物理內(nèi)存不足的時(shí)候就會(huì)被回收,一般時(shí)候整個(gè)操作系統(tǒng)內(nèi)存占用在15%-30%之間都是可調(diào)控的,基本不用擔(dān)心這個(gè)問(wèn)題,但是為了容災(zāi)性代碼依然需要做一些判斷處理。

垃圾回收的回收機(jī)制是通過(guò)代數(shù)來(lái)實(shí)現(xiàn)。

為優(yōu)化垃圾回收器的性能,將托管堆分為三代:第 0 代、第 1 代和第 2 代,因此它可以單獨(dú)處理長(zhǎng)生存期和短生存期對(duì)象。

第 0 代。 這是最年輕的代,其中包含短生存期對(duì)象。 短生存期對(duì)象的一個(gè)示例是臨時(shí)變量。 垃圾回收最常發(fā)生在此代中。

第 1 代。 這一代包含短生存期對(duì)象并用作短生存期對(duì)象和長(zhǎng)生存期對(duì)象之間的緩沖區(qū)。

第 2 代。 這一代包含長(zhǎng)生存期對(duì)象。 長(zhǎng)生存期對(duì)象的一個(gè)示例是服務(wù)器應(yīng)用程序中的一個(gè)包含在進(jìn)程期間處于活動(dòng)狀態(tài)的靜態(tài)數(shù)據(jù)的對(duì)象。

垃圾回收中未回收的對(duì)象也稱(chēng)為幸存者,并會(huì)被提升到下一代:

第 0 代垃圾回收中未被回收的對(duì)象將會(huì)升級(jí)至第 1 代。
第 1 代垃圾回收中未被回收的對(duì)象將會(huì)升級(jí)至第 2 代。
第 2 代垃圾回收中未被回收的對(duì)象將仍保留在第 2 代。

因?yàn)榈?0 代和第 1 代中的對(duì)象的生存期較短,因此,這些代被稱(chēng)為“暫時(shí)代”。

垃圾回收的過(guò)程:

標(biāo)記階段,找到并創(chuàng)建所有活動(dòng)對(duì)象的列表。

重定位階段,用于更新對(duì)將要壓縮的對(duì)象的引用。

壓縮階段,用于回收由死對(duì)象占用的空間,并壓縮幸存的對(duì)象。 壓縮階段將垃圾回收中幸存下來(lái)的對(duì)象移至段中時(shí)間較早的一端。

因?yàn)榈?2 代回收可以占用多個(gè)段,所以可以將已提升到第 2 代中的對(duì)象移動(dòng)到時(shí)間較早的段中。 可以將第 1 代幸存者和第 2 代幸存者都移動(dòng)到不同的段,因?yàn)樗鼈円驯惶嵘降?2 代。

然后后臺(tái)垃圾回收、大型對(duì)象堆、被動(dòng)回收、延遲模式等可以作為了解。

與我們寫(xiě)代碼息息相關(guān)

垃圾回收機(jī)制與我們寫(xiě)代碼息息相關(guān)的部分是:

  1. 強(qiáng)引用和弱引用
  2. 針對(duì)共享 Web 承載優(yōu)化
  3. 垃圾回收和性能
  4. 應(yīng)用程序域資源監(jiān)視

看完這篇關(guān)于c#中托管和非托管資源詳解的文章,如果覺(jué)得文章內(nèi)容寫(xiě)得不錯(cuò)的話,可以把他分享出去給更多人看到。

向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)容。

AI