自動記憶體管理是公共語言運行時在托管執行程序中提供的服務之一,公共語言運行時的垃圾回收器為應用程式管理記憶體
的分配和釋放,對開發人員而言,在開發托管應用程式時不必撰寫執行記憶體管理任務代碼,
分配記憶體
初始化新行程時,運行時會為行程保留一個連續的地址空間區域,這個保留的地址空間被稱為托管堆,托管堆維護著一個指標,用它指向堆中分配的下一個物件的地址,初始時,該指標設定為指向托管堆的基礎地址,托管堆上包含所有的參考型別,應用程式在創建第一個參考型別時,將為托管堆的基址中的型別分配記憶體,應用程式創建下一個物件時,垃圾回收器在緊接第一個物件后面的地址空間內為它分配記憶體,只要地址空間可用,垃圾回收器就會繼續以這種方式為新物件分配空間,
在托管堆中分配記憶體要比非托管堆記憶體分配速度快,由于運行時通過為指標添加值來為物件分配記憶體,這個速度幾乎與堆疊中分配記憶體一樣快,另外由于連續分配的新物件在托管堆中是連續存盤,所以應用程式可以快速訪問這些物件,
釋放記憶體
垃圾回收器的優化引擎根據所執行的分配決定執行回收的最佳時間,垃圾回收器在執行回收時,會釋放應用程式不再使用的物件的記憶體,它通過檢查應用程式的根來確定不再使用的物件,每個應用程式都有一組根,每個根或者參考托管堆中的物件設定為空,應用程式的根包含執行緒堆疊上的靜態欄位、區域變數和引數以及CPU暫存器,垃圾回收器可以訪問由實時編輯器(JIT)和運行時維護的活動根的串列,垃圾回收器對照此串列檢查應用程式的根,并在此程序中創建一個圖表,在其中包含所有可從這個根中訪問的物件,
不在該圖表中的物件無法從應用程式的根中訪問,垃圾回收器會考慮無法訪問的物件垃圾,并釋放為他們分配記憶體,在回收中,垃圾回收器檢查托管堆,查找無法訪問物件占據的地址空間塊,發現無法訪問的物件時,它就使用復制功能來壓縮記憶體中可以訪問的物件,釋放分配給不可訪問物件的地址空間,在壓縮了可訪問物件的記憶體后,垃圾回收器就會做出指標更正,一邊應用程式的根指向新地址中的物件,它會將托管堆指標定位至最后一個可訪問物件以后,
注意:垃圾回收器只要發現大量無法訪問的物件時,才會壓縮記憶體,如果托管堆中的所有物件均未被回收,則不需要壓縮記憶體,
為了改進性能,運行時(JIT)為單獨堆中的大型物件分配記憶體,垃圾回收器會自動釋放大型物件的記憶體,為了避免動記憶體中大型物件,不會壓縮此記憶體,
級別和性能
為了優化垃圾回收器的性能,將托管堆分為三代:第0代,第1代,第2代,運行時的垃圾回收演算法基于以下幾個普通原理,這些垃圾回收方案的原理已在軟體實驗中得到驗證,首先,壓縮托管堆的一部分記憶體要比壓縮整個托管堆速度塊,其次,比較新物件生存期比較短,而比較老的物件生存期比較長,最后,比較新的物件趨向于相互關聯,并同時由應用程式訪問,
運行時的垃圾回收器將新物件存盤在第0級中,在應用程式生存期的早期創建物件如果未被回收,則升級并存盤在第1級和第2級中,
實際上,垃圾回收器在第0級托管堆已滿時執行回收,如果應用程式在第0級托管堆已滿時嘗試新建物件,垃圾回收器將會發現第0級已沒有可分配給物件地址空間,垃圾回收器就執行回收操作,釋放第0級托管堆中的地址空間,垃圾回收器從第0級托管堆中的物件開始執行回收,
垃圾回收器執行第0級托管堆的回收后,會壓縮可訪問物件記憶體,然后垃圾回收器升級這些物件,并考慮第1級退管堆的這部分,因為未被回收的物件一般為比較長的生存期,所以將他們升級至更高級別,因此垃圾回收器每次回收第0級的托管堆,不會檢查第1級和第2級托管堆中的物件,
在執行第0級托管堆的首次回收并把可訪問的物件升級至第1級托管堆后,垃圾回收器將考慮第0級托管堆的其余部分,它將繼續為第0級的托管堆中的新物件分配記憶體,直至第0級托管堆無法在分配地址后在執行另外一次的垃圾回收為止,此時,垃圾回收器的優化引擎會決定是否需要檢測比較舊的級別中的物件,如:垃圾回收器發現0級托管堆中釋放后的記憶體,不能再創建新的物件,垃圾回收器就會執行第1級托管堆的回收,然后再執行第2級托管堆的回收,如果這樣仍不能回收足夠的記憶體,垃圾回收器將執行第2,1和0級托管堆的回收,每次回收后,垃圾回收器都會壓縮第0級托管堆中的可訪問物件并將他們升級到第1級托管堆,第1級托管堆中未被回收的物件將會升級到第2級托管堆,由于垃圾回收器只支持三個級別,因此第2級托管堆中未被回收的物件繼續保留再第2級托管堆中,直到在將來的回收中確定題目為無法訪問為止,
為非托管資源釋放記憶體
對于應用程式創建的大多數物件,可以依賴垃圾回收器自動執行必要的記憶體管理任務,但是,非托管資源需要顯示清除,最常用的非托管堆資源型別時包裝作業系統資源的物件,如:檔案句柄,視窗句柄或網路連接,雖然垃圾回收器可以跟蹤封裝非托管堆資源的托管物件的生存期,但卻無法具體了解如果清理資源,創建封裝非托管資源的物件時,建議在公共Dispose方法中提供必要的代碼用以清理非托管堆資源,通過提供Dispose方法,物件的用戶可以在使用完物件后顯示釋放記憶體,使用封裝非托管資源的物件時,應在不使用的時候呼叫Dispose()方法釋放,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/288523.html
標籤:.NET技术
