到底是什么原因導致我的進程崩潰?


當你你有1000個w3wp.exe文件在eventviewer中意外停止,或者您的進程以某種奇怪的未定義方式退出,您不知道原因。
當一個進程崩潰或退出時,將觸發一個稱為EPR(Exit process)的特殊事件,因此使用類似於windbg.exe文件我們可以附加到進程中,等待epr被拋出,然后進行內存轉儲。安裝windows調試工具時,會得到一個名為adplus的vbs腳本,它將為您自動執行此操作,並打印進程生命周期中發生的大多數異常的日志。
調試提示:當您在-crash模式下打開一個轉儲時,您將自動定位到崩潰發生時處於活動狀態的線程(最有可能是可疑的線程)。如果您切換線程並想返回出錯線程,請鍵入~列出所有線程,錯誤線程將被標記為一個點。
如果dump只顯示進程中的一個活動線程,並且該線程是主線程,則該進程可能被外部的東西(運行狀況監視、低系統內存、iisreset等)終止

不分先后順序,以下是我們看到的支持率最高的一些:

Stack Overflow Exceptions

當為線程的堆棧分配的內存用完時,將發生堆棧溢出異常。默認情況下,它是1 MB,所以你的調用堆棧可能很深,所以大多數情況下發生這種情況是因為無限遞歸,也就是說,function調用FunctionB,后者再次調用FunctionB,后者再次調用FunctionB。。。沒有停止條件。
不幸的是,異常處理應用程序塊的錯誤使用是一個相當常見的模糊的無限遞歸情況。想象一下這個場景:你的應用程序得到一個異常,異常處理程序啟動,你已經將它設置為記錄到一個文件中。在記錄日志時,您會得到某種類型的異常(比如訪問被拒絕),並且您已經設置了異常處理程序來處理此異常。在這種情況下,您將在一個無限遞歸循環中處理一個異常,拋出另一個異常,處理它,拋出另一個。。。你明白要點了。這個故事的寓意是什么?不要在異常處理程序中使用異常處理程序來處理異常。
如果您運行“kb2000”(查看本機堆棧)和“!clrstack”(從sos.dll要查看托管堆棧),您可以找到遞歸模式以跟蹤遞歸發生的位置/原因。

Out Of Memory Exceptions

大多數情況下,發生內存不足異常是由設計問題引起的,在設計問題中,緩存或會話作用域中存儲的內存過多。如果以正確的方式使用緩存,那么緩存對於提高性能是非常有用的,也就是說,緩存的數據最多,而且緩存的時間不會超過需要的時間。在舊的ASP中,如果將對象存儲在session范圍內,就會出現問題,相信我,這是一種偽裝,因為開發人員只在session范圍內存儲了最必要的項。例如,在會話范圍內存儲大型數據集通常會適得其反,因為您減少了網站可以處理的並發用戶數,而且當內存足夠大時,在緩存中進行垃圾收集和搜索所需的時間可能比從數據庫中請求數據的開銷要多真的需要它。
在何時應該在會話/緩存中存儲內容以及何時不應該存儲時,這里沒有一刀切的解決方案。最好的做法是在早期階段,確定應用程序需要能夠處理的用戶數,並在此基礎上確定每個用戶可以允許的存儲量。然后對超過最大用戶數的用戶進行壓力測試,以確保你能應付。最好是對處於會話狀態的對象進行壓力測試,看看性能如何。不同的用戶數量不同。
在生產過程中,內存問題是很難解決的,因為它們通常需要大量的重新設計,所以在早期階段花費一分錢可以節省很多錢。
調試提示:運行!dumpheap -type System.Web.Caching.Cache獲取緩存根,然后對這些地址進行!do objsize,以了解您在緩存中為不同的應用程序存儲了多少。(注意:InProc會話狀態也存儲在緩存中)

Unhandled exception in COM Component

如果應用程序調用本機COM組件,如果其中出現未經處理的異常,則可能會崩潰。 例如,如果您引用的是已釋放的內存或類似內存。 kb2000將在堆棧上顯示COM組件,這樣您就可以縮小它的范圍。
 
Native heap corruption
 
 
這與GC漏洞一起是最棘手的問題。當有人寫入不應該寫入的位置時,本機堆損壞。這樣做的問題是,當寫入錯誤地址的代碼執行時,您不會看到錯誤,而是當其他人試圖以正確的方式訪問該內存地址時。換句話說,在“小偷”出現很久之后。寫入的位置可以是堆,或者更糟的是,一個存儲代碼的位置(這樣指令就會被覆蓋),或者是堆棧,這樣代碼就可以調用到不知道的地方。最常見的情況是,當您在緩沖區或其他類似的邊界之外寫入時,就會發生這種情況。
當您因為堆損壞而崩潰時,出錯的堆棧通常位於ntdll中的堆分配函數中,要解決此問題,您需要使用GFlags或PageHeap運行,以便能夠當場抓到小偷。然而,之所以如此難以捕捉,是因為這些問題非常隨機,很難重現。
 
Managed Heap Corruption
 
托管堆損壞是發生在托管堆上的堆損壞。同樣,在這里,你會在問題發生很久之后才發現問題。如果有人重寫不允許的托管堆的一部分,則會發生托管堆損壞。通常不能在托管代碼中緩沖溢出。如果您有一個byte[]並且試圖在邊界外寫入,那么您將得到一個indexautofrange異常或類似的異常。托管堆損壞的最常見原因是,名為PInvoke的代碼在某種類型的緩沖區中傳遞,但緩沖區太小。PInvoked函數寫入緩沖區,但寫入的內容超出緩沖區的范圍,並寫入托管堆上的下一個對象。稍后,當垃圾回收器執行其工作時,它會嘗試遍歷堆,但情況會變糟,因此進程會崩潰。
如果發生崩潰,並且活動堆棧的頂部包含GC函數,則開始在代碼中查找pinvoke,看看是否傳遞的緩沖區太小。
 
Fatal Execution Engine Exceptions
 
致命的執行引擎異常相當罕見,但當它們發生時,通常是一個bug。這意味着,由於某種原因,我們進入了一些在CLR中不應該出現的代碼,CLR決定,如果有人出現在這里,讓我們拋出一個致命的執行引擎異常並死亡,因為我們無法從這一點恢復過來。在事件日志中,這將被記錄為執行引擎異常發生,並且列出的地址將准確地告訴代碼中它發生的位置。如果您找到其中一個,但找不到有關它的知識庫文章,請聯系支持人員,最好提供崩潰轉儲,因為這將大大加快解決問題的時間。
 
GC Holes
 
這些也是相當罕見的。CLR的非托管部分有一個指向托管內存的指針,並且“忘記”告訴GC有關它的信息,因此GC不知道保留它(如果沒有其他根)或跟蹤它的移動,這意味着如果GC在“錯誤的時間”發生,指針可能會指向任何地方,從而造成很大的破壞。

No available memory left

如果你的進程死了,同時你看到內存/available兆字節的大幅度下降,達到0,這可能會導致進程崩潰。當然,這里的任務是檢查是什么進程偷走了內存。

External process kills/Recycles the process

無數次,當我有一個客戶在崩潰模式下連接adplus時,我會發現內存轉儲,進程被外部的東西殺死了。我想添加這個問題,因為通常當你對崩潰進行故障排除時,這並不是你要排除的崩潰的真正原因(只有在極少數情況下),而是有人運行iisreset或者在不知道你有一個調試程序等待崩潰的情況下殺死了進程。所以如果你正在排除一個崩潰並得到一個內存轉儲。檢查事件日志以確保沒有人運行iisreset,因此這是導致崩潰轉儲的原因。這樣可以節省你幾個小時去尋找車禍的罪魁禍首。
另一個奇怪的地方是安裝了某種監視軟件來監視服務器是否按預期服務頁面,如果沒有,則關閉進程。但通常這也會在eventviewer中記錄發生的事件。

Health monitoring settings

當然,我知道我們設置為每24小時循環一次進程,或者如果服務器空閑超過20分鍾,但無論如何值得一提的是,因為我們經常遇到這些問題。同樣,這里,通常會在事件日志中記錄一個事件,說明進程被回收的原因,但故事的寓意是在iis或中簡要查看應用程序池的運行狀況監視設置計算機配置看看你打開了什么回收意見,這樣你以后就不會有驚喜了。
發生崩潰的原因比上面提到的要多,但它們通常都是相當模糊的,所以我希望這篇文章能讓你對如何開始尋找進程突然失效有一點了解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM