.Net的GC垃圾回收原理及實(shí)現(xiàn)
一、先了解下必備的知識(shí)前提
內(nèi)存中的托管與非托管,可簡單理解為:
托管:可借助GC從內(nèi)存中釋放的數(shù)據(jù)對(duì)象(以下要描述的內(nèi)容點(diǎn))
非托管:必須手工借助Dispose釋放資源(實(shí)現(xiàn)自IDisposable)的對(duì)象
內(nèi)存中有棧和堆的概念區(qū)分,僅簡單說明:
棧:先進(jìn)后出 的特點(diǎn)(這里不再詳細(xì)闡述)
堆:存放數(shù)據(jù)對(duì)象實(shí)例的內(nèi)存空間(以下要描述的內(nèi)容點(diǎn))
二、.Net GC的簡單描述
GC垃圾回收是對(duì)于內(nèi)存堆的處理過程。
當(dāng)一個(gè)應(yīng)用程序進(jìn)程創(chuàng)建時(shí),會(huì)為此應(yīng)用程序在物理內(nèi)存堆中分配一塊虛擬的連續(xù)性內(nèi)存空間,以供應(yīng)用程序后續(xù)運(yùn)行時(shí)存放產(chǎn)生的數(shù)據(jù)對(duì)象實(shí)例。
GC是一個(gè)獨(dú)立的進(jìn)程,用來自動(dòng)維護(hù)管理內(nèi)存堆中的空間分配和釋放。它通過一個(gè)或多個(gè)線程進(jìn)行垃圾回收,默認(rèn)啟用后臺(tái)線程垃圾回收。(關(guān)于前臺(tái)線程與后臺(tái)線程,可參考其它)
三、.Net平臺(tái)的GC垃圾回收,什么時(shí)候會(huì)被觸發(fā)呢?
1、當(dāng)被分配的堆中虛擬內(nèi)存空間不夠用時(shí),系統(tǒng)會(huì)自動(dòng) 回收/壓縮/擴(kuò)大 被分配的虛擬內(nèi)存塊,以適應(yīng)新產(chǎn)生的數(shù)據(jù)對(duì)象存儲(chǔ)。
2、當(dāng)整個(gè)物理內(nèi)存不夠用時(shí),系統(tǒng)會(huì)自動(dòng) 回收/壓縮 各個(gè)進(jìn)程占用的內(nèi)存空間,以適應(yīng)新產(chǎn)生的數(shù)據(jù)對(duì)象存儲(chǔ)。
3、當(dāng)應(yīng)用程序中手動(dòng)觸發(fā)GC回收時(shí),GC按照手動(dòng)指定的方式進(jìn)行垃圾回收。
四、從作用域上 去理解堆中的代
先這樣去理解吧
假設(shè)一個(gè)實(shí)例變量聲明時(shí)的作用域較大,那它就不會(huì)馬上被回收,因?yàn)樽饔糜虼蟮囊蛩?,有可能后續(xù)程序時(shí)常還會(huì)被用到。
假設(shè)一個(gè)實(shí)例變量聲明時(shí)的作用域較小,那它就有可能被優(yōu)先回收,因?yàn)樯嬷芷谳^短,過了作用域范圍,此變量不會(huì)再被使用。
假設(shè)一個(gè)靜態(tài)的或全局的作用域變量,那它通常不會(huì)被回收,因?yàn)檫@樣的全局聲明會(huì)在任意代碼段長期被使用。
所以,為了更好的回收,堆中將各數(shù)據(jù)對(duì)象實(shí)例歸納為:0代、1代、2代
0代:臨時(shí)或最新創(chuàng)建的數(shù)據(jù)對(duì)象實(shí)例。最常被回收的對(duì)象實(shí)例。
1代:一段時(shí)間內(nèi)再次使用的數(shù)據(jù)對(duì)象實(shí)例,生命周期較長的數(shù)據(jù)對(duì)象實(shí)例。較少被回收的對(duì)象實(shí)例。
2代:常住內(nèi)存的對(duì)象實(shí)例,如:靜態(tài)類型,全局作用域等的對(duì)象實(shí)例。通常為應(yīng)用程序退出后回收。
五、堆中對(duì)象 在代之間的轉(zhuǎn)移:幸存者的提升
應(yīng)用程序持續(xù)運(yùn)行中,
新創(chuàng)建的對(duì)象首先被放在0代中,當(dāng)運(yùn)行一段時(shí)間后,有些變量超出了自己所在的作用域,不會(huì)再被使用,會(huì)被GC清理;
由于有些變量作用域大,當(dāng)前還未超出自己所在的作用域,接下來可能還會(huì)被使用,所以GC不會(huì)清理;
0代中,有些數(shù)據(jù)對(duì)象實(shí)例會(huì)被GC清理,有些數(shù)據(jù)實(shí)例對(duì)象未被GC清理,那么,未被GC清理的數(shù)據(jù)對(duì)象實(shí)例,我們稱它為幸存者。
此時(shí),0代中的幸存者會(huì)被轉(zhuǎn)移到1代中(想想上面提到1代存放的是哪類對(duì)象實(shí)例...);
那么,以此類推,長期/處處被使用的對(duì)象實(shí)例,就會(huì)從1代中轉(zhuǎn)移到2代中;
因此,2代中存放的通常為靜態(tài)或全局作用域或長期被使用到的對(duì)象實(shí)例。
六、GC是如何去確定要清理的對(duì)象實(shí)例?
GC在堆中生成各對(duì)象間的結(jié)構(gòu)圖,作為回收對(duì)象的依據(jù),找出非活動(dòng)的對(duì)象。
所有數(shù)據(jù)對(duì)象實(shí)例之間的關(guān)聯(lián)引用關(guān)系,都會(huì)生成一個(gè)完整的結(jié)構(gòu)圖,一些不在結(jié)構(gòu)圖中的 或超出所在作用域的 或不再被繼續(xù)使用的對(duì)象實(shí)例,被稱為非活動(dòng)對(duì)象。被視為GC要清理的對(duì)象。
準(zhǔn)確的說:
- 堆棧根
- 垃圾回收句柄
- 靜態(tài)數(shù)據(jù)
七、手動(dòng)GC垃圾回收
在某些不常見的情況下,強(qiáng)制回收可提高應(yīng)用程序的性能。在此,可使用 GC.Collect 方法強(qiáng)制執(zhí)行垃圾回收,從而誘導(dǎo)垃圾回收。
注意,是誘導(dǎo),而不是即刻回收。
為了考慮到應(yīng)用程序當(dāng)前的穩(wěn)定運(yùn)行,執(zhí)行GC.Collect并不一定馬上產(chǎn)生效果,這里僅僅是一個(gè)觸發(fā),會(huì)去收集將要回收的對(duì)象,回收動(dòng)作會(huì)在未來某個(gè)合適的時(shí)間段進(jìn)行。(當(dāng)然,也可以強(qiáng)制阻塞式回收,這里略過)
(思考一下:無用的實(shí)例=null,是否告知GC為可回收的對(duì)象?再GC.Collect()后的效果。)
關(guān)于 GC.Collect 方法的參數(shù),會(huì)用到上面提到的概念及場(chǎng)景:
- 對(duì)指定的代進(jìn)行回收
- 指定回收次數(shù)
- 強(qiáng)制回收 或 擇機(jī)回收
- 阻塞式回收 或 后臺(tái)線程回收
- 壓縮 或 清理
(阻塞式回收方式:都先停一停,先讓我回收完)
當(dāng)然,通常建議:0代,擇機(jī),后臺(tái)回收(阻塞式風(fēng)險(xiǎn)太大,通常選擇擇機(jī)方式,具體自我考量)
八、內(nèi)存堆中的弱引用
當(dāng)應(yīng)用程序正在執(zhí)行使用的對(duì)象,GC是不可能回收的,那么,就認(rèn)為應(yīng)用程序?qū)υ搶?duì)象具有強(qiáng)引用。
強(qiáng)引用:應(yīng)用程序正在使用的對(duì)象實(shí)例,不能被GC回收。
弱引用:應(yīng)用程序暫時(shí)沒使用的對(duì)象實(shí)例,暫時(shí)可被GC定義為可回收的實(shí)例,在回收之前,也可被應(yīng)用程序再次使用后變?yōu)閺?qiáng)引用。
假設(shè)一個(gè)對(duì)象實(shí)例被GC清理后,后續(xù)又被再次用到的場(chǎng)景,就會(huì)重新創(chuàng)建對(duì)象實(shí)例,那如果這個(gè)對(duì)象實(shí)例又比較大,這樣的頻繁創(chuàng)建... ...
當(dāng)然還有優(yōu)化的空間,所以,弱引用優(yōu)化了以上場(chǎng)景。
弱引用的優(yōu)點(diǎn):對(duì)于頻繁創(chuàng)建的大實(shí)例,弱類型可以做到一次創(chuàng)建多次使用,避免大對(duì)象實(shí)例多次創(chuàng)建的性能消耗。
(對(duì)于小對(duì)象使用弱類型,所帶來的對(duì)對(duì)象管理上的性能消耗,是否值得)
若要對(duì)某對(duì)象建立弱引用,使用要跟蹤的對(duì)象實(shí)例創(chuàng)建 WeakReference。 然后將 Target 屬性設(shè)置為該對(duì)象,將該對(duì)象的原始引用設(shè)置為 null。(參考官方文檔)
也就是說:我們可以自定義控制哪些對(duì)象實(shí)例要不要暫時(shí)不被GC垃圾回收。
九、多應(yīng)用共享內(nèi)存時(shí)的垃圾回收
當(dāng)多個(gè)應(yīng)用程序在一臺(tái)主機(jī)同時(shí)運(yùn)行時(shí),對(duì)內(nèi)存空間大小的分配,建議是靈活可變的,以達(dá)到各應(yīng)用程序?qū)?nèi)存利用的平衡及穩(wěn)定性。
如果啟用 gcTrimCommitOnLowMemory 設(shè)置,垃圾回收器會(huì)計(jì)算系統(tǒng)內(nèi)存負(fù)載,并在負(fù)載達(dá)到 90% 時(shí)進(jìn)入修整模式。除非負(fù)載下降到不到 85%,否則會(huì)一直處于修整模式。
如果條件允許,垃圾回收器可以決定 gcTrimCommitOnLowMemory 設(shè)置對(duì)當(dāng)前應(yīng)用沒有幫助并忽略它。
如下啟用 gcTrimCommitOnLowMemory 設(shè)置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<runtime>
<gcTrimCommitOnLowMemory enabled="true"/>
</runtime>
</configuration>
到此這篇關(guān)于.Net的GC垃圾回收原理及實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān).Net GC垃圾回收 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ASP.NET 文件斷點(diǎn)續(xù)傳實(shí)現(xiàn)代碼
在文件下載的時(shí)候,使用斷點(diǎn)續(xù)傳可以將上次未下載完成的文件繼續(xù)下載,該功能在開發(fā)文件下載的時(shí)候非常重要。這里我將介紹一種比較簡單的斷點(diǎn)續(xù)傳功能的實(shí)現(xiàn)方法,僅供初學(xué)者參考使用2012-06-06
ASP.NET:把a(bǔ)shx寫到類庫里并在頁面上調(diào)用的具體方法
最近在調(diào)整博客的架構(gòu),進(jìn)一步把表現(xiàn)和業(yè)務(wù)分離,所以要把之前用ashx搞的那些Http Handler放到類庫中,下面是具體的步驟及代碼2013-06-06
asp.net 擴(kuò)展GridView 增加單選按鈕列的代碼
asp.net 擴(kuò)展GridView 增加單選按鈕列的代碼2010-02-02
Win2008 server + IIS7 設(shè)置身份模擬(ASP.NET impersonation)
IIS7 與 IIS 6 相比有了很大的改動(dòng),原來在 IIS 6 下可以的設(shè)置到了 IIS 7 下有的會(huì)發(fā)生變化。身份模擬的配置上,IIS7 和 IIS6有很大不同,網(wǎng)上IIS6的身份模擬的文章比較多,但介紹IIS7的比較少,我把的一些折騰的經(jīng)驗(yàn)在這篇博客中寫下來,以供參考2011-10-10
微軟官方SqlHelper類 數(shù)據(jù)庫輔助操作類
本文主要介紹微軟官方的數(shù)據(jù)庫操作類極其使用方法,幫助大家利用已經(jīng)非常成熟的類庫來進(jìn)行快速開發(fā)。2016-03-03
ASP.NET Core 3框架揭秘之 異步線程無法使用IServiceProvider問題
這篇文章主要介紹了ASP.NET Core 3框架揭秘之異步線程無法使用IServiceProvider問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12
ASP.NET?MVC打印表格并實(shí)現(xiàn)部分視圖表格打印
這篇文章介紹了ASP.NET?MVC打印表格并實(shí)現(xiàn)部分視圖表格打印的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08
詳解ASP.NET Core 2.0 路由引擎之網(wǎng)址生成(譯)
這篇文章主要介紹了詳解ASP.NET Core 2.0 路由引擎之網(wǎng)址生成(譯),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11
ASP.net(c#)用類的思想實(shí)現(xiàn)插入數(shù)據(jù)到ACCESS例子
ASP.net(c#)用類的思想實(shí)現(xiàn)插入數(shù)據(jù)到ACCESS例子...2007-07-07

