性能監視器是Windows自帶的系統資源和性能監視工具. 性能監視器能夠量化地提供CPU使用率, 內存分配狀況, 異常派發情況, 線程調度頻率等信息. ASP.NET能夠提供每秒鐘的請求數目, 請求響應時間等等. 性能監視器能夠監視一段時間內上述資源的利用情況, 提供平均值和峰值。
性能監視器有助于獲取關于性能的具體指標, 監視問題出現時系統資源的變化情況. 通過檢查性能監視器中一些重要計數器的變化情況, 往往能夠找到一些比較有用的線索. 比如比較ASP.NET每秒請求數目, 請求響應時間和CPU利用率是否有相同的變化曲線就能看出性能是否跟負載相關。
解決性能問題的時候, 往往會讓客戶添加下面一些計數器進行性能收集。
分析性能日志的時候, 重點觀察下面這些計數器.
=============
Process object中的計數器可以根據目標進程分析內存, CPU, 線程數目和handle數目. 選出問題的目標進程, 然后分析目標進程的下面一些計數器.
%Processor Time
-------------------
該計數器是該進程占用CPU資源的指標. 即便進程繁忙的時候, CPU平均占用率應該在80%以內. 如果超過該數值, 可以認為程序發生了高CPU的問題. 另外一種問題是CPU波動幅度大. 雖然平均占用率不高, 但是上下跳動頻繁. 在某一個短時間段里面, 會有連續高CPU的情況出現.
Handle Count
------------------
該計數器記錄了當前進程使用的kernel object handle數量. Kernel object是重要的系統資源. 當程序進入穩定運行狀態的時候, Handle Count數量也應該維持在一個穩定的區間. 如果發現Handle Count在整個程序周期內總體趨勢連續向上, 應該考慮程序是否有Handle Leak.
ID Process
------------------
該計數器記錄了目標進程的進程ID. 你可能覺得奇怪, ID有什么好觀察的? 進程ID是用來觀察程序是否有重啟發生. 比如ASP.NET工作進程可能會自動回收. 由于進程名都相同, 所以只有通過進程ID來判斷是否有重新啟動現象. 如果ID有變化, 那么而看看程序是否發生崩潰或者Recycle.
Private Bytes
------------------
該計數器記錄了當前通過VirtualAlloc API進行的, Commit了的Memory數量. 無論是直接調用API申請的內存, Heap Manager申請的內存, 還是CLR的managed heap, 都算在里面. 跟Handle Count一樣, 如果在整個程序周期內總體趨勢連續向上, 說明有Memory Leak.
Virtual Bytes
------------------
該計數器記錄了當前進程申請成功的用戶態總內存地址, 包括DLL/EXE占用的地址和通過VirtualAlloc API進行的, Reserve了的內存地址數量, 所以該計數器應該總大于Private Bytes. 一般說來, Virtual Bytes與Private Bytes的變化大致一致. 由于內存分片的存在, Virtual Bytes與Private Bytes一般保持一個相對穩定的比例關系. 當Virtual Bytes與Private Bytes的比例大于2的時候, 程序往往有比較嚴重的內存地址分片.
==============
Processor object記錄系統中芯片的負載情況. 由于普通程序并不可以綁定到某個具體的CPU上執行, 所以在多CPU機器上觀察Total Instance也就足夠了.
%Processor Time
----------------------
該計數器跟Process下的%Processor Time的意義一樣, 不過這里記錄的不是針對具體的某一個進程, 而是整個系統. 通過把該計數器跟Process下的同名計數器一起比較, 就能看出系統的高CPU問題是否是由于單一的某個進程導致的.
==============
System object記錄系統中一個整體的統計信息. 所以不區分instance. 通過比較System object下的counter和其他counter的變化趨勢, 往往能看出一些線索.
Context Switch/ sec
--------------------
Context Switch標示了系統中整體線程的調度, 切換頻率. 線程切換是開銷比較大的操作. 頻繁的線程切換回導致大量CPU周期被浪費. 所以當看到高CPU的時候, 一定要與Context Switch一起比較. 如果兩者有相同的變化趨勢, 高CPU往往是由于contention(線路爭奪)導致的, 而不是死循環.
Exception Dispatches/ sec
-------------------
Exception Dispatches表示了系統中異常派發, 處理的頻繁程度. 跟線程切換一樣, 異常處理也需要大量的CPU開銷. 分析方法跟Context Swith雷同.
File Data Operations/ sec
-------------------
File Data Operations記錄了當前系統中磁盤文件讀寫的頻繁程度. 通過觀察該計數器跟其他性能指針的變化趨勢, 能夠判斷磁盤文件操作是否是性能瓶頸. 類似的計數器還有Network Interface, Bytes Total/ sec
=============
Memory object記錄了當前系統中整體內存的統計信息.
Avaiable Mbytes 和 Committed Bytes
---------------------
Available Mbytes記錄了當前剩余的物理內存數量. Committed Bytes記錄了所有進程commit的內存數量. 結合兩個計數器可以觀察到:
Free System Page Table Entries, Pool Paged Bytes 和 Pool Nonpaged Bytes
--------------------
這三個計數器可以衡量核心態空閑內存的數量. 特別是當使用/3GB開關后, 核心態內存地址被壓縮, 容易導致核心態內存不足, 繼而引發一些非常奇怪的問題.
=============
.NET CLR Memory object記錄了CLR進程中跟CLR相關的內存信息. 該類別下的所有計數器都很有趣, 意思也非常直接. 建議用一個例子程序進行測試和研究. 下面是兩個最常用的計數器.
Bytes in all heaps
----------------------
Bytes in all heaps 記錄了上次GC發生時所統計到的, 進程中不能被回收的所有CLR object占用的內存空間. 該計數器不是實時的, 每次GC發生的時候, 該計數器才更新. 與同一進程的Process下的Private Bytes比較, 可以區分出managed heap和native memory的變化情況. 對于memory leak, 便于區分是managed heap的leak, 還是native memory 的leak.
%Time in GC
%Time in GC記錄了GC發生的頻繁程度. 一般來說15%以內算比較正常. 當超過20%時, 說明GC發生過于頻繁. 由于GC不僅帶來很高的CPU開銷, 而且還需要掛起目標進程的CLR線程, 所以高頻率GC是非常危險的. 通過跟CPU利用率和其他性能指標的比較, 往往能夠看出GC對性能的影響. 高頻率的GC往往因為:
ASP.NET 支持兩組性能計數器:系統和應用程序。前者在 ASP.NET 性能計數器對象中的 PerfMon 中公開;后者在 ASP.NET applications 性能對象中公開。ASP.NET 性能對象中的 State Server sessions 計數器(僅適用于在其中運行狀態服務器的服務器計算機)和 ASP.NET Applications 性能對象中的 Sessions 計數器(僅適用于進程中發生的用戶會話)之間存在很大的差異。
在監視 ASP.NET Web 應用程序的性能時,應該始終跟蹤下表中列出的性能計數器。
性能對象 | 性能計數器 |
ASP.NET | Application Restarts |
ASP.NET | Requests Queued |
ASP.NET | Worker Process Restarts |
ASP.NET Applications | Errors Total |
ASP.NET Applications | Requests/Sec |
Processor | % CPU Utilization |
ASP.NET 支持以下 ASP.NET 系統性能計數器。它們匯集 Web 服務器計算機上所有 ASP.NET 應用程序的信息,或者它們通常應用于運行相同應用程序的 ASP.NET 服務器的系統。它們可能包含 Web 場和 Web 園。