引言
GC 作為CLR的垃圾回收器,讓程序員可以把更多的關注度放在業務上而不是垃圾回收(內存回收)上。其實很多語言也有類似的東東,
如Java也有JIT 等等
GC基本概念
- 垃圾回收機制的算法有好多種,GC為Mark-Sweep算法。
- GC中分為三代,來優化管理不同生命周期的對象。
- 大部分的對象在Gen0就死掉了。
- Gen0 和Gen 1 又叫作ephemeral generations (短命代,個人翻譯意見 )
- 大於85,000bytes的對象會被直接分配到Large object heap上,且在Gen2回收時才會被回收。
GC回收時機
- 系統內存不足
- Gen0 沒有足夠的空間需要申請新的空間(應該是segment)
- 手動條用GC.Collect()
GC步驟
當進行一次垃圾回收操作時,會分三個步驟進行:
1. 先假設所有對象都是垃圾;
2. 標記出正在使用的對象; (會先找GC Roots,然后遍歷GC Heap上的每個對象,生成一個對象List)
標記依據:
a. 被變量引用的對象,仍然在作用域中。
比如某個類中的某個方法,方法執行了一半,如果此時發生垃圾回收,那么方法塊中的變量都在作用域中,那么它們都會被標記為正在使用。
b. 被另一個對象引用的對象,仍在使用中。
3. 壓縮:釋放第二步中未標記的對象(不再使用,即“垃圾”)並將使用中的對象轉移到連續的內存塊中。
只要垃圾回收器釋放了能釋放的對象,它就會壓縮剩余的對象,把它們都移回堆的端部,再一次形成一個連續的塊。(這里其實有個更新引用或者說指針的操作)
GC處理Finalizalbe對象工作原理
上圖假設是新創建對象為Gen0 代的且為Finalizable的對象,首次就會被回收(如局部的且<85,000bytes的對象)。
實現 Finalize 方法或析構函數對性能可能會有負面影響,因此應避免不必要地使用它們。用 Finalize 方法回收對象使用的內存需要至少兩次垃圾回收。當垃圾回收器執行回收時,它只回收沒有終結器的不可訪問對象的內存。這時,它不能回收具有終結器的不可訪問對象。它改為將這些對象的項從終止隊列中移除並將它們放置在標為准備終止的對象列表中。該列表中的項指向托管堆中准備被調用其終止代碼的對象。垃圾回收器為此列表中的對象調用 Finalize 方法,然后,將這些項從列表中移除。后來的垃圾回收將確定終止的對象確實是垃圾,因為標為准備終止對象的列表中的項不再指向它們。在后來的垃圾回收中,實際上回收了對象的內存。
GC分類
從工作模式角度來看:
兩大類:WorkStation GC 和 Server GC
分類依據:
WorkStation GC 是默認的工作方式,如果你是單處理器的機器,那么這是你唯一的選擇,並且及時你配置了Concurrent選項為True,也不會生效。
Server GC 在多處理器的機器上才會出現,且默認出現在Aps.net寄存服務中。他會為每個處理器都創建一個GC Heap,並且會並行執行回收操作。該模式的GC可以最大化吞吐量和較好的收縮性(4處理器+)
<configuration>
<runtime>
<gcServer enabled="true" />
</runtime>
</configuration>可以通過以上配置方式或者通過native code 類指定GC 工作模式
HRESULT CorBindToRuntimeEx( LPWSTR pwszVersion,
LPWSTR pwszBuildFlavor, // use “svr” for server mode,
// “wks” or NULL for workstation
DWORD flags,
REFCLSID rclsid,
REFIID riid,
LPVOID* ppv );
下表為GC為GC heap向系統申請時的基本單位Segment的默認值,注意是默認值,這些值會隨着程序的實際執行情況,GC動態調整。這里了解下即可,另外正是由於有segment的概念所以回出現內存碎片的問題,所以GC在垃圾回收過程中會進行內存整理,以減少內存碎片,提高內存使用率。
32-bit |
64-bit |
|
Workstation GC |
16 MB |
256 MB |
Server GC |
64 MB |
4 GB |
Server GC with > 4 logical CPUs |
32 MB |
2 GB |
Server GC with > 8 logical CPUs |
16 MB |
1 GB |
從工作方式,工作側重點和實現上來看:
兩類:Foreground GC,Concurrent GC | BackGround GC(側重於Gen2 GC性能優化,正常情況Gen0 ,Gen1的速度都比較快)
Foreground GC工作的時候絕對是.net 程序要向系統申請分配Gc Heap空間啦,所以它的優先級最高。一旦它運行,其他所有線程都會被掛起來。
通過配置文件開啟或者關閉並發和后台模式,(同一個配置項)
<configuration>
<runtime>
<gcConcurrent enabled="false" />
</runtime>
</configuration
In workstation or server garbage collection, you can enable concurrent garbage collection , which enables threads to run concurrently with a dedicated thread that performs the garbage collection for most of the duration of the collection. This option affects only garbage collections in generation 2; generations 0 and 1 are always non-concurrent because they finish very fast.
Server GC 和Workstation GC都可以開啟並發GC。在GC回收的過程中大部分時間用戶線程可以並發運行。但這中效果只能影響到2帶GC的過程,因為0代1代的時間太短了。
Concurrent WS | Non-Concurrent WS | BackGround WS (替代並發) |
Server GC | Server GC Background(替代並發) | |
出現時間 | .net 1+ | .net 1+<x<.net.4 | .net 4+ | .net 1+ | .net 4.5.1+ |
設計目標 | 在吞吐量和界面相應速度上尋找平衡點 | 最大化吞吐量 | 在WS的設計基礎上,優化gen2 GC性能 | 多處理器機器上使用多線程處理相同類型的請求以便最大化服務程序吞吐量 | 優化gen2 GC性能 |
GC Heap數量 | 1 | 1 | 1 | 1 per processor (HT aware) | 1 per processor (HT aware) |
GC threads | 分配空間的線程會觸發GC, | 分配空間的線程會觸發GC線程 | 每個處理器都有一個專職的GC線程 | 每個處理器都有一個專職的GC background線程 | |
GC線程優先權 | 和工作線程具有相同的優先權 | 和工作線程具有相同的優先權 | background GC線程與工作線程有相同優先級,但都低於前台GC線程 | THREAD_PRIORITY_HIGHEST | background GC線程與工作線程有相同優先級,但都低於前台GC線程 |
工作線程(非GC線程) | GC工作過程中短暫多次掛起 | GC工作過程中一直被掛起 | GC工作過程中短暫多次掛起,較並發性能更加(針對Gen2的) | GC工作過程中會被掛起 | GC工作過程中短暫多次掛起,較並發性能更加(針對Gen2的) ephemeral generation 的前台GC工作時會掛起其他所有線程 |
配置方式 | <gcConcurrent enabled="true"> | <gcConcurrent enabled="false"> | <gcConcurrent enabled="false"> | <gcServer enabled="true"> | <gcConcurrent enabled="false"> |
是否會超時 | 會 | 不會 |
----------------------------------------------------------------------------------------------
Workstation GC
-------------------------------------------------------------------------------------------------
Server garbage collection
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
Background workstation garbage collection
-------------------------------------------------------------------------------------------------
Background server garbage collection
-------------------------------------------------------------------------------------------------
其他相關
編程的內存模型中我們會接觸到“堆”和“棧”兩個部分。每個線程都有自己的棧,但共享堆(當然不是直接跨線程訪問的意思,只能理解為共存在堆上)。
性能計數
What is the cost of a garbage collection? How can I keep this cost at a minimum?
You can measure the GC cost for your application with a few different counters. Remember that all of these counters are updated at the end of a collection which means that if you use averages they may not be valid after a long time of inactivity.
.NET CLR Memory\% time in GC - This counter measures the amount of CPU time you spend in GC and it is calculated as (CPU time for GC/CPU time since last GC)
.NET CLR Memory\# Induced GC – This is the number of garbage collections that have occurred as a result of someone calling GC.Collect(). Ideally this should be 0 since inducing full collections means that you spend more time in the GC, and also because the GC continuously adapts itself to the allocation patterns in the application, and performing manual GCs skews this optimization.
.NET CLR Memory\# Gen X collections – This counter displays the amount of collections that have been performed for a given generation. Since the cost of gen 2 collections is high compared to Gen 1 and Gen 0 you want to have as few Gen 2 collections per Gen 1 and Gen 0 collections as possible. A ratio of 1:10:100 is pretty good.
The most common causes for high CPU in GC or a high number of Gen 2 collections compared to 1 and 0 is high allocation of large objects and letting objects survive multiple generations because of improper use of finalizers or because finalizable objects are not disposed of correctly in the application.
參考
How does the GC work and what are the sizes of the different generations?
http://blogs.msdn.com/maoni/archive/2004/06/15/156626.aspx
http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx
垃圾回收翻譯系列(√)