C#探索之路(4):淺析C#中的托管、非托管堆棧與垃圾回收
一、C#托管服務下的幾個重要概念:
1、 托管代碼:
1、使用 .NET 時,我們經(jīng)常會遇到“托管代碼”這個術語。
2、簡而言之,托管代碼就是執(zhí)行過程交由運行時管理的代碼。
2、CLR階段:
1、在托管服務下,相關的運行時稱為公共語言運行時 (CLR)。
2、不管使用的是哪種實現(xiàn)(例如 Mono、.NET Framework 或 .NET Core/.NET 5+)。 CLR 負責提取托管代碼、將其編譯成機器代碼,然后執(zhí)行它。
3、 除此之外,運行時還提供多個重要服務,例如自動內(nèi)存管理(也也就是后面提到GC機制)、安全邊界、類型安全,等等。
3、非托管代碼:
1、概念:
在公共語言運行庫環(huán)境的外部,由操作系統(tǒng)直接執(zhí)行的代碼
2、區(qū)別:
非托管代碼必須提供自己的垃圾回收、類型檢查、安全支持等服務,它與托管代碼不同,后者從公共語言運行庫中獲得這些服務,而非托管代碼是在運行庫之外運行的代碼。例如COM 組件、ActiveX 接口和 Win32 API 函數(shù)都是非托管代碼的示例。
3、C#官方文檔做出的說明:
在非托管環(huán)境中,程序員需要親自負責處理相當多的事情。 實際的程序在本質(zhì)上是操作系統(tǒng) (OS) 載入內(nèi)存,然后啟動的二進制代碼。 其他任何工作 - 從內(nèi)存管理到安全考慮因素 - 對于程序員來說是一個不小的負擔。
托管代碼是使用可在 .NET 上運行的一種高級語言(例如 C#、Visual Basic、F# 等)編寫的。 使用相應的編譯器編譯以這些語言編寫的代碼時,無法獲得機器代碼, 而是獲得中間語言代碼,然后運行時會對其進行編譯并將其執(zhí)行。 C++ 是這條規(guī)則的一個例外,因為它也能夠生成可在 Windows 上運行的本機非托管二進制代碼。
4、中間語言(IL、CIL、MSIL):
1、簡稱:
什么是“中間語言”(簡稱 IL)?中間語言有時也稱為公共中間語言 (CIL) 或 Microsoft 中間語言 (MSIL)。
2、概念:
中間語言其實意如其名,意思就是一個從高級語言轉(zhuǎn)成機器碼中間的過度語言,因為大體的流程其實是這么一回事
①開發(fā)者使用的高級語言編寫功能實現(xiàn)代碼
---->②LC(Language Complier我們通常稱之為解釋器,也就是編譯器內(nèi)置的解釋器)
---->③MSIL(IL\CIL)---->通過CLR和JIT實時編譯運行將IL代碼轉(zhuǎn)成對應的機器碼(即二進制碼)
---->④機器通過執(zhí)行機器碼實現(xiàn)對應的功能效果;
(看到了這,我恍然大悟,大學科目原來是這么用的啊,可算是圓回來了hhhhhhh,“*(不能明說的字)” 原來硬件是這么用的啊,寄存器,CPU其實說白了就是一個機器碼執(zhí)行器,這么說其實有問題,對于cpu大家可以參考這個鏈接:cpu的相關概念)
5、托管代碼互操作性
當然,CLR 允許越過托管與非托管環(huán)境之間的邊界,同時,即使在基類庫中,也有很多代碼可以做到這一點。 這稱為互操作性,簡稱 interop。 例如,使用這些機制可以包裝某個非托管庫以及調(diào)用該庫。 但是,請務必注意,如果采取這種方法,當代碼越過運行時的邊界時,實際的執(zhí)行管理將再次交接到托管代碼,因而需要遵守相同的限制。
與此類似,C# 語言可讓你利用所謂的不安全上下文(指定執(zhí)行過程不由 CLR 管理的代碼片段),在代碼中直接使用非托管構(gòu)造,例如指針。
至于托管代碼的互操作性,我目前還不是很明確但是查究到了這么一篇文章【轉(zhuǎn)帖】 CLR 全面透徹解析:托管和本機代碼互操作性,講述的挺好的,那我不經(jīng)發(fā)出了疑問,那是不是有的Unity的C#的熱更方案就有用到這個托管代碼的互操作性呢?提出一個問題(這個問題以后有待考究),有了解或者使用過這個大佬的博友看到過,希望給出對應的解釋和回答,或者在評論區(qū)貼上對應的鏈接,不甚感激?。。。?br>
二、垃圾回收機制:
雜談:
以前談到C#中的GC(Garbage Collector-垃圾收集器),僅就內(nèi)存而言的垃圾收集。我們在自己心中都有一個概念就是C#中有這么一種內(nèi)存管理方案來幫助開發(fā)者自動取管理內(nèi)存,釋放掉我們沒有使用的內(nèi)存資源,從而把內(nèi)存資源分配給我們正在使用的對象上去;
但是當我回過頭來了解這個垃圾回收機制的時候,我發(fā)現(xiàn)了一個很有意思的事情,當我去查詢相關的資料的時候我發(fā)現(xiàn),這其中的原理真的是一環(huán)扣一環(huán),還環(huán)環(huán)不一樣,我的內(nèi)心:(TM*燃起來了!)。相反導致這個有意思的方法勾起了我的探索欲,這到底是個什么玩意兒,究竟神奇在哪;
1、垃圾回收的基本概念:
.NET 的垃圾回收器管理應用程序的內(nèi)存分配和釋放。 每當有對象新建時,公共語言運行時都會從托管堆為對象分配內(nèi)存。 只要托管堆中有地址空間,運行時就會繼續(xù)為新對象分配空間。 不過,內(nèi)存并不是無限的。 垃圾回收器最終必須執(zhí)行垃圾回收來釋放一些內(nèi)存。 垃圾回收器的優(yōu)化引擎會根據(jù)所執(zhí)行的分配來確定執(zhí)行回收的最佳時機。 執(zhí)行回收時,垃圾回收器會在托管堆中檢查應用程序不再使用的對象,然后執(zhí)行必要的操作來回收其內(nèi)存。
概括:就是GC會幫你自動管理內(nèi)存,分配內(nèi)存,回收內(nèi)存,采用的就是對應的GC的算法。
2、垃圾回收帶來的優(yōu)點:
垃圾回收器具有以下優(yōu)點:
- 開發(fā)人員不必手動釋放內(nèi)存。
- 有效分配托管堆上的對象。
- 回收不再使用的對象,清除它們的內(nèi)存,并保留內(nèi)存以用于將來分配。 托管對象會自動獲取干凈的內(nèi)容來開始,因此,它們的構(gòu)造函數(shù)不必對每個數(shù)據(jù)字段進行初始化。
- 通過確保對象不能自己使用分配給另一個對象的內(nèi)存來提供內(nèi)存安全。
- 在公共語言運行時 (CLR) 中,垃圾回收器 (GC) 用作自動內(nèi)存管理器。 垃圾回收器管理應用程序的內(nèi)存分配和釋放。 對于使用托管代碼的開發(fā)人員而言,這就意味著不必編寫執(zhí)行內(nèi)存管理任務的代碼。 自動內(nèi)存管理可解決常見問題,例如,忘記釋放對象并導致內(nèi)存泄漏,或嘗試訪問已釋放對象的內(nèi)存。
3、垃圾回收機制具體做了什么:
垃圾回收主要有這么幾個階段:
- 標記階段,找到并創(chuàng)建所有活動對象的列表。
- 重定位階段,用于更新對將要壓縮的對象的引用。
- 壓縮階段,用于回收由死對象占用的空間,并壓縮幸存的對象。 壓縮階段將垃圾回收中幸存下來的對象移至段中時間較早的一端。
- 因為第 2 代回收可以占用多個段,所以可以將已提升到第 2 代中的對象移動到時間較早的段中。 可以將第 1 代幸存者和第 2 代幸存者都移動到不同的段,因為它們已被提升到第 2 代。
垃圾回收器使用以下信息來確定對象是否為活動對象:
- 由實時 (JIT) 編譯器和堆棧查看器提供的堆棧變量。 JIT 優(yōu)化可以延長或縮短報告給垃圾回收器的堆棧變量內(nèi)的代碼的區(qū)域。
- 指向托管對象且可由用戶代碼或公共語言運行時分配的句柄。
- 應用程序域中可能引用其他對象的靜態(tài)對象。 每個應用程序域都會跟蹤其靜態(tài)對象。
然而這里面所指代的第幾代第幾代實際上就是C#官方文檔所講述到的幸存與提升,感興趣的朋友可以到官方文檔里面了解其中的細節(jié),因為牽扯的內(nèi)容太多太雜,我覺得太雜反而不利于去理解其中的核心過程,就不做贅述了,請網(wǎng)友自行查閱吧。
在查詢資料的時候看到了其他博主形象的把官方文檔的內(nèi)容通過示意圖畫出來了,還挺有意思的:
大概傳達的一個意思就是:
GC:“你們不用這塊內(nèi)存了是吧?那我把你們排擠出去了奧,你們誰還要續(xù)租使用的,可以繼續(xù)保留,但是前提是此時已經(jīng)不是原來的內(nèi)存了,已經(jīng)是一塊新分配的內(nèi)存了”;
為了方便了解其中的內(nèi)容,可以試著用租房與房東之間的關系來具體理解;
該圖片轉(zhuǎn)載自:
C#關于托管資源GC垃圾回收與非托管資源繼承 IDisposable接口 實現(xiàn) Dispose方法釋放非托管資源
該圖片轉(zhuǎn)載自:
C#垃圾回收機制GC
4、垃圾回收機制的注意事項:
-
對于應用程序創(chuàng)建的大多數(shù)對象,可以依賴垃圾回收器自動執(zhí)行必要的內(nèi)存管理任務。 但是,非托管資源需要顯式清除。
-
最常用的非托管資源類型是包裝操作系統(tǒng)資源的對象,例如,文件句柄、窗口句柄或網(wǎng)絡連接。
-
創(chuàng)建封裝非托管資源的對象時,建議在公共 Dispose 方法中提供必要的代碼以清理非托管資源。 通過提供 Dispose 方法,對象的用戶可以在使用完對象后顯式調(diào)用釋放其內(nèi)存。
-
使用using和try/finally清理資源,
-
所有非托管資源的類型必須顯式地使用IDisposable接口的Dispose()來釋放。所有封裝或使用了非托管資源的類型都實現(xiàn)了IDisposable,這些類型在終結(jié)器中也會調(diào)用Dispose(),以便在忘記的時候仍能保證正常釋放資源。不過這些資源將在內(nèi)存中停留更長時間,應用程序也會變成資源消耗大戶。(此條目收錄自C# 學習筆記 .Net資源管理)
若想使用一個可銷毀的對象,那么using語句能夠以最簡單的方式保證你的對象可以正常銷毀。using語句將生成一個try/finally塊,包裹住分配的對象。這兩段代碼生成的IL完全一致:
參考鏈接:
cpu的相關概念
C#關于托管資源GC垃圾回收與非托管資源繼承 IDisposable接口 實現(xiàn) Dispose方法釋放非托管資源
C# 學習筆記 .Net資源管理
C#垃圾回收機制GC
C#官方文檔之垃圾回收的托管服務相關概念說明
C#官方文檔之垃圾回收的相關概念文檔說明
【轉(zhuǎn)帖】 CLR 全面透徹解析:托管和本機代碼互操作性
c#中的托管、非托管、垃圾回收、using
以上呢,便是我對托管、非托管堆棧與C#垃圾回收作出的簡要的描述,希望能夠?qū)δ阌兴鶐椭鷡 也希望你能夠點贊、評論吖~ 你們的點贊、評論就是我前進的動力!
公眾號:平平無奇代碼猴
也可以搜索:Jackiie_wang 公眾號,歡迎大家關注!歡迎催更!留言!
作者:ProMer_Wang
鏈接:https://blog.csdn.net/qq_43801020/article/details/127601735文章來源:http://www.zghlxwxcb.cn/news/detail-453005.html
本文為ProMer_Wang的原創(chuàng)文章,著作權(quán)歸作者所有,轉(zhuǎn)載請注明原文出處,歡迎轉(zhuǎn)載!文章來源地址http://www.zghlxwxcb.cn/news/detail-453005.html
到了這里,關于C#探索之路(4):淺析C#中的托管、非托管堆棧與垃圾回收的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!