您好,登錄后才能下訂單哦!
小編這次要給大家分享的是c#中托管和非托管資源詳解,文章內容豐富,感興趣的小伙伴可以來了解一下,希望大家閱讀完這篇文章之后能夠有所收獲。
前言
c# 托管和非托管比較重要,因為這涉及到資源的釋放。
現在只要在計算機上運行的,無論玩出什么花來,整個什么概念,逃不過輸入數據修改數據輸出數據(計算機本質),這里面有個數據的輸入,那么我們的內存有限啊,這里面就牽扯到數據釋放。
看下c# 的垃圾回收是怎么樣的。
了解垃圾回收之前首先要了解數據,了解數據需要了解數據類型啊,數據類型分為值類型還有引用類型。
windows 使用一個虛擬尋址系統,該系統把程序可用的內存地址映射到硬件內存中的實際地址上,這些任務完全由windows 在后臺管理。我們的程序運行在操作系統上,那么我們作為程序員關系的就是這個虛擬尋址系統。
這東西有什么用呢?
比如32位系統中,每個進程所占用的最多4G(4G這樣來的,2^32,4個字節),那么這個程序如果進行管理的這4G,它不需要知道在硬件地址是多少。
比如這個進程申請了1k內存,那么這個進程管理的實際是從0到1k的虛擬內存,而不需要知道這個硬件物理內存地址是多少,有一個可以直接證明的就是我們寫c++輸出指針的時候,發現指針輸出1千多,
你覺得可能是物理內存地址的1千多嗎?默默的打開資源管理看看現在占用多少內存。
默認情況下,32 位計算機上的每個進程都具有 2 GB 的用戶模式虛擬地址空間。這里解釋一下,每個進程2個G是虛擬地址,就是在這個進程維護一個2G的虛擬地址,并不是實際占有2G的硬件內存地址。
盜一張圖:
虛擬地址有三種狀態:
狀態 | 描述 |
Free | 該內存塊沒有引用關系,可用于分配。 |
保留 | 內存塊可供你使用,并且不能用于任何其他分配請求。 但是,在該內存塊提交之前,你無法將數據存儲到其中。 |
已提交 | 內存塊已指派給物理存儲。 |
那么這個虛擬內存上又分了堆和棧,棧上存儲值類型,堆上存儲引用類型。
他們的存儲方式不一樣。
下面是棧:
棧是這樣子的先用高位后用低為,比如申請80000,先用的就是80000 直到為0為止。
{ int a=10; double b=100.0; }
如上圖,80000用完了,這時候棧指針指向80000。
現在int a了,int是4個字節,這時候棧指針減4,到79996這個位置。
然后是double,double 為8個字節,這時候棧指針減8,以此類推。
然后如果變量超出作用域,那么這個時候就會被垃圾回收,棧指針增加8,然后增加4。(記得棧指針增加的時候[垃圾回收]并不會去把已經使用的地址重置為0,只有類型申明的時候才重置為0,然后再賦值)
下面是引用類型:
堆是這樣子的,已用的內存地址小,空閑的內存地址大。
舉個栗子:
{ student a; a=new student; }
首先運行student a,這個時候存儲的是引用地址,也就是4個字節,存放在棧上。
然后運行a=new student(),首先假設student使用64個字節,那么在堆上就申請連續的64個字節,然后把首地址傳遞賦值給a。
上面非常大的程度簡化了程序的內存分配,引用類型垃圾回收的一個簡化版就是——當一個引用變量超出作用域的時候,它會從棧中刪除,但是引用對象的數據保存在堆中,只有沒有任何一個引用變量指向引用對象的時候那么這個引用對象才會回收。
好的,知道了數據存儲是怎么樣的,來看一下垃圾回收吧。
正文
關于垃圾回收,.net 文檔是這樣介紹的。
.NET 的垃圾回收器管理應用程序的內存分配和釋放。
每當有對象新建時,公共語言運行時都會從托管堆為對象分配內存。
只要托管堆中有地址空間,運行時就會繼續為新對象分配空間。
不過,內存并不是無限的。 垃圾回收器最終必須執行垃圾回收來釋放一些內存。
垃圾回收器的優化引擎會根據所執行的分配來確定執行回收的最佳時機。
執行回收時,垃圾回收器會在托管堆中檢查應用程序不再使用的對象,然后執行必要的操作來回收其內存。
那么什么時候垃圾回收呢?
1.系統具有低的物理內存。 這是通過 OS 的內存不足通知或主機指示的內存不足檢測出來。
2.由托管堆上已分配的對象使用的內存超出了可接受的閾值。 隨著進程的運行,此閾值會不斷地進行調整。
3.調用 GC.Collect 方法。 幾乎在所有情況下,你都不必調用此方法,因為垃圾回收器會持續運行。 此方法主要用于特殊情況和測試。
第三個.net 平臺會幫我們處理,第二個托管堆會幫我們自我調整,關鍵是第1個如何物理內存不足的時候就會被回收,一般時候整個操作系統內存占用在15%-30%之間都是可調控的,基本不用擔心這個問題,但是為了容災性代碼依然需要做一些判斷處理。
垃圾回收的回收機制是通過代數來實現。
為優化垃圾回收器的性能,將托管堆分為三代:第 0 代、第 1 代和第 2 代,因此它可以單獨處理長生存期和短生存期對象。
第 0 代。 這是最年輕的代,其中包含短生存期對象。 短生存期對象的一個示例是臨時變量。 垃圾回收最常發生在此代中。
第 1 代。 這一代包含短生存期對象并用作短生存期對象和長生存期對象之間的緩沖區。
第 2 代。 這一代包含長生存期對象。 長生存期對象的一個示例是服務器應用程序中的一個包含在進程期間處于活動狀態的靜態數據的對象。
垃圾回收中未回收的對象也稱為幸存者,并會被提升到下一代:
第 0 代垃圾回收中未被回收的對象將會升級至第 1 代。
第 1 代垃圾回收中未被回收的對象將會升級至第 2 代。
第 2 代垃圾回收中未被回收的對象將仍保留在第 2 代。
因為第 0 代和第 1 代中的對象的生存期較短,因此,這些代被稱為“暫時代”。
垃圾回收的過程:
標記階段,找到并創建所有活動對象的列表。
重定位階段,用于更新對將要壓縮的對象的引用。
壓縮階段,用于回收由死對象占用的空間,并壓縮幸存的對象。 壓縮階段將垃圾回收中幸存下來的對象移至段中時間較早的一端。
因為第 2 代回收可以占用多個段,所以可以將已提升到第 2 代中的對象移動到時間較早的段中。 可以將第 1 代幸存者和第 2 代幸存者都移動到不同的段,因為它們已被提升到第 2 代。
然后后臺垃圾回收、大型對象堆、被動回收、延遲模式等可以作為了解。
與我們寫代碼息息相關
垃圾回收機制與我們寫代碼息息相關的部分是:
看完這篇關于c#中托管和非托管資源詳解的文章,如果覺得文章內容寫得不錯的話,可以把他分享出去給更多人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。