工具出現掛死問題
1.問題描述
工具出現掛死問題,巡檢IIS發現以下異常日志
現網系統日志:
事件類型: 錯誤
事件來源: .NET Runtime
描述:
Application: DiyRingSet30Tool.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an internal error in the .NET Runtime at IP 791F7E06 (79140000) with exit code 80131506.
說明:此日志可以通過“開始”-“所有程序”-“管理工具”-“事件查看器”-“應用程序”,觀察類型為錯誤或者警告的日志,一般出現錯誤日志都是應用程序錯誤導致的,請引起重視
2.修復方法
在工具的配置文件中新增以下紅色的配置節點內容
<configuration>
<runtime>
<gcConcurrent enabled="false"/>
</runtime>
</configuration>
3.問題原因
原因:正在引用的對象被取消引用由垃圾回收器在公共語言運行庫4(CLR4)中發生的問題。因此,垃圾回收或應用程序嘗試訪問已發布的對象的過程中發生訪問沖突。
4.相關知識說明
垃圾回收器可自行優化並且適用於多種方案。 可基於工作負荷的特征使用配置文件來設置垃圾回收的類型。 CLR垃圾回收可以做內存移動也可以不做移動。不做移動時也稱為“清掃”,清掃的代價要比做壓縮的代價低一些,因為他不需要復制移動內存。CLR 提供了以下類型的垃圾回收:
4.1運行時GC工作模式
1)工作站模式:關閉並發的工作站GC、開啟並發的工作站GC
2)服務器模式:服務器GC
工作站垃圾回收,用於所有客戶端工作站和獨立 PC。 這是運行時配置架構中的 <gcServer> 元素的默認設置。既可以是並發的,也可以是非並發的。 並發垃圾回收使托管線程能夠在垃圾回收期間繼續操作。從 .NET Framework 4 開始,后台垃圾回收取代了並發垃圾回收。
服務器垃圾回收,用於需要高吞吐量和可伸縮性的服務器應用程序。 服務器垃圾回收既可以是非並發或后台運行。
4.2各個GC模式的設計目標
1) 關閉並發的工作站GC為高性能服務器的高吞吐量做了優化。我們在垃圾回收時根據分配和復活模式做動態調優因此可以程序運行時自動調優GC的工作效率。
2) 開啟並發的工作站GC是為要求精確響應時間的交互式應用程序設計的。開啟並發使垃圾回收造成的工作進程暫停時間縮短。 這個目的是用一些內存和CPU換來的,因此在這種模式下垃圾回收需要做的工作略多一點需要的回收時間會略長一些。
3) 服務器GC,從名字上我們可以看出這種工作模式是為服務器應用程序設計的;典型的場景是你有一個工作線程池這些線程做着相似的處理。例如:做處理同樣的請求或者處理相同類型的事務。所有的線程使用幾乎相同的分配模式。服務器GC是為要求高吞吐量的和高擴展性的多處理器服務器設計的
4.3各個GC模式如何工作
工作站模式(workstation mode) 。
1)這種模式下GC假設機器上運行的其他應用程序對CPU資源要求不高,並發模式是默認的工作站模式,該模式下垃圾回收器分配一個額外的后台線程在應用程序運行時並發回收對象。一個線程因為分配對象造成第0代超出預算時,垃圾回收器掛起所有線程(不會掛起運行本機代碼的線程、並發模式允許托管線程在回收期間運行),判斷需要回收哪些代,如果需要回收第2代,就會增加第0代的大小。然后應用程序恢復執行。
2)回收發生在觸發垃圾回收的用戶線程上,並保留相同優先級。 因為用戶線程通常以普通優先級運行,所以垃圾回收器(在普通優先級線程上運行)必須與其他線程競爭 CPU 時間。
3)工作站垃圾回收始終用在只有一個處理器的計算機上,而不管 <gcServer> 設置如何。 如果你指定服務器垃圾回收,則 CLR 會使用工作站垃圾回收,並禁用並發。
服務器模式 (servermode)。
1)這種模式下GC假設機器上沒有運行其他應用程序,所有的CPU都可以用來進行垃圾回收操作。在這種情況下虛擬內存按照CPU數量划分區域分開對待,每個CPU上都運行一個GC線程負責回收自己的區域。 為每個 CPU 提供一個用於執行垃圾回收的一個堆和專用線程,並將同時回收這些堆。 每個堆都包含一個小對象堆和一個大對象堆,並且所有的堆都可由用戶代碼訪問。不同堆上的對象可以相互引用。
2)回收發生在以 THREAD_PRIORITY_HIGHEST 優先級運行的多個專用線程上。
3)因為多個垃圾回收線程一起工作,所以對於相同大小的堆,服務器垃圾回收比工作站垃圾回收更快一些。
4)服務器垃圾回收通常具有更大的段。
5)服務器垃圾回收會占用大量資源。 例如,如果在一台具有 4 個處理器的計算機上運行了 12 個進程,則在它們都使用服務器垃圾回收的情況下,將有 48 個專用垃圾回收線程。 在高內存加載的情況下,如果所有進程開始執行垃圾回收,則垃圾回收器將要計划 48 個線程。
並發垃圾回收
讓我們從關閉並發的工作站GC說起,其執行流程如下:
1) 一個托管進程做內存分配
2) 分配完所有可用的內存
3) 觸發了垃圾回收,垃圾回收操作在做分配的線程上運行
4) GC調用SuspendEE來掛起所有的托管線程
5) GC開始工作
6) GC調用RestartEE來重啟工作托管進程
7) 托管進程繼續運行
圖:演示了在單獨的專用線程上執行的並發垃圾回收
你可以看到在第5步中所有的托管線程都停止執行來等待垃圾回收完成工作。SuspendEE不會掛起本地線程(native threads)。
在開啟並發垃圾回收(Concurrent GC)時,最大的差異是掛起和重啟。並發垃圾回收通過最大程度地減少因回收引起的暫停,使交互應用程序能夠更快地響應。 在運行並發垃圾回收線程的大多數時間,托管線程可以在回收期間繼續運行。 這意味着並發GC暫停時間非常少。
因此開啟並發的垃圾回收會盡可能少的執行垃圾回收,執行時間也非常短。在剩余的時間中如果需要托管線程可以運行和分配內存。開啟並發時我們會在開始時給0代一個很大的分配預算來保證垃圾回收運行期間有足夠的空間分配對象。(GC中的每一代都有一個“分配預算”的概念。每一代的“分配預算”在運行時是動態調整的。因為我們經常在0代上做分配,你可以想象0代預算超支了,這樣就會觸發垃圾回收。這里的預算和GC堆的段大小完全不是一回事,預算比段大小要小得多。)
盡管如此,如果在並發回收運行中托管線程需要分配過多的內存,線程也會被堵塞直到回收完成。(在並發垃圾回收期間在堆上為小對象分配空間的能力受到在並發垃圾回收啟動時臨時段上保留的對象的限制。 一旦到達臨時段的末尾,將必須等待並發垃圾回收完成,同時將掛起需要執行小對象分配的托管線程。)
在並發垃圾回收中,允許托管的線程在回收期間運行,記住0代和1代回收非常快,所以此選項只影響2代回收,不影響0代和1代,即在做0,1代回收時是不會做並發回收的。只是在2代回收時才會並發回收。
並發垃圾回收具有一個稍微大點的工作集(與非並發垃圾回收相比),這是因為你可以在並發回收期間分配對象。 但是,這會影響性能,原因是分配的對象將會成為你的工作集的一部分。 實質上,並發垃圾回收會犧牲一些 CPU 和內存來換取更短的暫停。
后台工作站垃圾回收
后台垃圾回收只在 .NET Framework 4 及更高版本中可用。 在 .NET Framework 4 中,僅支持工作站垃圾回收。 從 .NET Framework 4.5 開始,后台垃圾回收可用於工作站和服務器垃圾回收。
圖:對工作站上的獨立專用線程執行的后台垃圾回收
后台垃圾回收期間對暫時代的回收稱為前台垃圾回收。 發生前台垃圾回收時,所有托管線程都將被掛起。當后台垃圾回收正在進行並且你已在第 0 代中分配了足夠的對象時,CLR 將執行第 0 代或第 1 代前台垃圾回收。 專用的后台垃圾回收線程將在常見的安全點上進行檢查以確定是否存在對前台垃圾回收的請求。 如果存在,則后台回收將掛起自身以便前台垃圾回收可以發生。 在前台垃圾回收完成之后,專用的后台垃圾回收線程和用戶線程將繼續。
在后台垃圾回收中,在進行第 2 代回收的過程中,將會根據需要收集暫時代(第 0 代和第 1 代)。
后台垃圾回收無法設置;它會自動運行並啟用並發垃圾回收。 后台垃圾回收是對並發垃圾回收的替代。 與並發垃圾回收一樣,后台垃圾回收是在一個專用線程上執行的並且只適用於第 2 代回收。
后台垃圾回收可以消除並發垃圾回收所帶來的分配限制,因為在后台垃圾回收期間,可發生暫時垃圾回收。 這意味着,后台垃圾回收可以移除暫時代中的死對象,而且還可以在第 1 代垃圾回收期間根據需要展開堆。
后台服務器垃圾回收
服務器垃圾回收,這種模式和工作站模式完全不同。我們會為每一個CPU創建一個回收線程。垃圾回收在這些線程上執行而不是在分配線程上,其工作流程如下:
1. 一個托管線程做回收
2. 分配達到閥值
3. 給GC線程發信號,讓GC線程做垃圾回收,等待回收結束
4. GC線程運行,結束時發出回收完成的信號(在回收過程中,所有的托管線程會像工作站模式中一樣被掛起)
5. 托管線程收到信號重新開始運行
從 .NET Framework 4.5 開始,后台服務器垃圾回收是服務器垃圾回收的默認模式。 若要選擇此模式,請在運行時配置架構中將 <gcServer> 元素的 enabled 特性設置為true。 此模式與后台工作站垃圾回收具有類似功能,但有一些不同之處。 后台工作區域垃圾回收使用一個專用的后台垃圾回收線程,而后台服務器垃圾回收使用多個線程,通常一個專用的線程用於一台邏輯處理器。 不同於工作站后台垃圾回收線程,這些線程不會超時。
圖:對服務器上的獨立專用線程執行的后台垃圾回收。
4.4如果配置各個垃圾回收模式
要關閉並發回收,在配置文件中添加下面配置項:
<configuration>
<runtime>
<gcConcurrent enabled="false"/>
</runtime>
</configuration>
要使用服務器GC,使用下面配置:
<configuration>
<runtime>
<gcServer enabled=“true"/>
</runtime>
</configuration>
5.應用場景說明
1)如果你在寫一個獨立的托管程序並且沒有做任何配置,默認情況下CLR 將運行工作站垃圾回收並啟用並發垃圾回收。 對於單處理器計算機和多處理器計算機都是如此。這會降低性能
2)如果應用程序是單線程並且涉及大量的用戶交互,請開啟並發垃圾回收,即不需要在配置文件中修改回收方式,便於應用程序不會因為執行垃圾回收而暫停
3)如果你的程序在宿主程序中運行,宿主可能會為程序選擇GC的工作模式。
4)如果運行應用程序的數百個實例,請考慮使用工作站垃圾回收並禁用並發垃圾回收。 這可以減少上下文切換,從而提高性能。
5)並發回收是為了給用戶更好的交互體驗,適合客戶端應用程序,但是同時要注意並發回收對性能有損害,使用更多地內存。
6)若要在運行多個進程時提高性能,請禁用並發垃圾回收。
7)在工作站或服務器垃圾回收中,你可以啟用並發垃圾回收,以便在大多數回收期間,讓各線程與執行垃圾回收的專用線程並發運行。 此選項只影響第 2 代中的垃圾回收;第 0 代和第 1 代中的垃圾回收始終是非並發的,因為它們完成的速度非常快。
6.參考網站
1)http://q.cnblogs.com/q/45625/
2)http://msdn.microsoft.com/zh-cn/library/at1stbec.aspx
3)http://www.cnblogs.com/yukaizhao/archive/2011/11/29/use-gc-effective-2.html
4)http://technet.microsoft.com/zh-CN/library/ee851764
5)http://blog.csdn.net/directionofear/article/details/8034133
6)http://msdn.microsoft.com/zh-cn/library/ee787088(v=vs.110).aspx