配置選項
在基於“less rope to hang yourself with”思想下,.NET 框架沒有給開發提供很多太多的配置選項。但在大多數情況下,GC會跟你的硬件配置,及可用資源以及程序自己的行為做調整。當然也提供一些高級的配置使用,但這取決於你程序的類型。
工作站與服務器
你首要的是為應用選擇是在工作站還是服務器模式下運行。
系統默認為工作站模式。在這種模式下,GC在觸發回收時,回收線程與當前主線程的優先級一樣。對於簡單的應用程序,特別是存在工作站里有多個托管進程需要做交互的情況下,以及單處理器的計算機上,這可能是唯一的選擇,你試圖修改任何配置對運行不會產生任何影響。
服務器模式則會給每個業務邏輯進程創建一個專用的線程。這個線程會運行在高優先級(THREAD_PRIORITY_HIGHEST),但平時這個線程會處於休眠狀態,一旦需要做GC就會被喚醒。完成GC后又會進入休眠。
此外,CLR還會為每個處理器分配一個單獨的堆。每個處理器堆里,包含一個小對象堆和大對象堆。從你的應用程序角度上看,你的代碼不知道引用的對象是屬於哪個堆上面的(他們都有相同的虛擬地址空間)。
使用多個堆有下一些優點
- 垃圾回收可以並行處理。每個GC線程處理一個對應的堆。這是的服務器模式的GC比工作站模式要快的原因。
- 某些情況下,分配速度會更快,尤其是將大對象相對分配在同一個堆上快。還有一些其他內部差異,比如內存段的大小,越大的段在做垃圾回收時時間也會越長。
你可以在App.config 文件里的
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
你要如何選擇工作站或者服務器模式嗎?
如果一個多處理器機器上只運行你的應用程序,那么最明智的選擇是:服務器模式。它在大多數情況下可以降低GC的延遲。
另一位方面,如果你的機器有多個托管進程的應用程序,則需要具體分析了。如果這幾個托管應用都采用服務器模式,那么會創建很多個高優先級的線程,這個會對線程調度產生沖突和影響。在這種情況下,最好使用工作站模式。
如果你真的想在同一個台機器里的多個應用程序開啟服務器GC模式,還有另外一種選擇,就是為應用程序綁定特定的CPU。
無論你選擇哪種模式,本書的大部分技巧都使用這兩種模式。
后台GC
修改后台GC配置會更改2代對象的回收策略。相對於0代和1代的回收的前台GC,它不會中斷當前應用里其他的線程執行。
后台GC在會而外創建一個線程用來處理2代對象的回收。這意味着,如果你同時開啟后台GC和服務器GC,你將為每個處理器創建2個線程來處理GC。但這沒啥大不了的,雖然進程里多了很多個線程,但這些線程在大部分時間里還是不工作的。
在你的應用執行的時候GC也可以同時進行,但在某些情況下,還是會發生阻塞。在這時,后台GC還是會將應用程序里的其它線程給掛起。
如果使用工作站模式,則始終開啟后台GC模式,從.NET4.5開始,默認情況下服務器GC模式下也會開啟,當然你也可以關閉它。
以下是關閉后台GC的配置
<configuration>
<runtime>
<gcConcurrent enabled="false"/>
</runtime>
</configuration>
實際上,我們很少有理由去禁用后台GC。如果你想通過禁用后台GC的線程來提高你的應用程序在CPU的占用率,但這個想法是不現實的。但如果是減少GC的延遲或者頻率可以考慮關閉它。
低延遲模式
如果你的應用希望在一段特定時間里高速執行,不希望被GC的2代回收打擾。你可以通過改變 GCSettings.LatencyMode 的設置來實現。
LowLatency—只能在工作站模式運行,它可以暫停2代回收。
SustainedLowLatency—可以在工作站和服務器模式下執行。它可以暫停完整的2代回收,但如果你開啟里后台GC模式,你還是可以在后台GC線程里對2代對象做回收。
這兩種模式都將大大的增加內存的消耗,因為它沒對內存做壓縮。如果你的應用需要消耗大量的內存,則最好避免開啟這兩個模式。
當你要准備進入低延遲模式前,最好手動執行一次完整的GC(GC.Collect(2, GCCollectionMode.Forced)。等離開低延遲模式后,也手動觸發一次完成GC。
默認情況下,是不需要開啟這個模式。只有你的程序執行時間不要被GC打擾才需要開啟,不用在全過程都開啟。舉個栗子:如果你有一個股票交易的高頻應用,在交易時間段里不希望發生GC回收暫停應用執行。但在股市交易結束后,你可以關閉這個模式進行完整的GC回收直到股市重新開市。
如果要開啟低延遲模式,至少要符合以下標准:
- 在正常執行期間,完整的垃圾回收操作是不可接受的
- 應用程序消耗的內存要遠小於可分配內存
- 應用程序在開啟低延遲模式后,要有足夠的內存撐到下一次手動執行完整回收或者重啟。
這是一個很少用的配置,如果你要使用請三思而后行,因為開啟之后會出現一些意想不到的后果。如果你認為還是有必要使用,請確保你的應用經過了充分測試。在開啟后,系統會產生更頻繁的0代和1代的回收操作,用來減少完整的回收,這可能會導致一些其他性能問題。這可能會導致解決了一個又另外產生了一個問題。
最后,請注意,低延遲模式不是一個保證。如果GC在做回收的時候仍然拋出了OutOfMemoryException異常,仍然有可能會不管你的配置選項,進行一次完整的GC回收。