Windows 效能監控器概述
Windows 效能監控器是一個 Microsoft 管理主控台 (MMC) 嵌入式管理單元,提供用於分析系統效能的工具。僅從一個單獨的控制台,即可即時監視應用程式和硬體效能,自訂要在日誌中收集的資料,定義警報和自動操作的閾值,產生報告以及以各種方式查看過去的效能資料。
啟動 Windows 效能監控器:開始-->運行—>輸入perfmon-->斷行符號
添加-儲存計數器設定:
在Windows 2003中,添加完計數器後,直接按Ctrl+S,就能將設定儲存為檔案的形式,方便下次直接查看,在Win7中來的不那麼直接。
開始-->運行-->輸入MMC-->檔案-->添加/刪除嵌入式管理單元-->選擇效能監控器-->添加,然後在效能(本地)中來添加你的計數器,這樣就可以儲存了,方便下次查看。
運行:
常用的監視計數器:
對象 |
計數器 |
說明 |
.NET CLR Exceptions |
# of Exceps Thrown / sec |
顯示每秒鐘拋出的異常數。這包括 .NET 異常和轉換為 .NET 異常的未受管異常。效能隨此數目的增大而下降。 |
.NET CLR Memory |
# Bytes in all Heaps |
顯示其他四個計數器的總和:Gen 0 堆大小、Gen 1 堆大小、Gen 2 堆大小以及大對象堆大小。此計數器表示 GC 堆上當前分配的記憶體(以位元組為單位)。此計數器的值總是比 Process\Private Bytes 的值小,Process\Private Bytes 對進程的 MEM_COMMIT 地區進行計數。Private Bytes minus # Bytes in all Heaps 就是由未受管對象提交的位元組數。 用於監視可能的記憶體流失,或者監視受管或未受管對象的記憶體使用量率是否過大。 |
.NET CLR Remoting |
Remote Calls/sec |
顯示每秒調用的遠端程序呼叫的數目。遠端程序呼叫是對調用方所在應用程式定義域之外的任何對象的調用。此計數器不是一段時間內的平均值;它顯示最近兩個樣本觀測值的差除以取樣間隔所得的結果。 |
.NET Data Provider for Oracle |
NumberOfFreeConnections |
串連池中可用串連的數量。 |
.NET Data Provider for SqlServer |
NumberOfFreeConnections |
串連池中可用串連的數量。 |
Process |
% Processor Time |
顯示所有進程線程用於執行指令的已用處理器時間的百分比。指令是電腦中的基本執行單位;線程是執行指令的對象;進程是運行程式時建立的對象。此計數中包含了處理某些硬體中斷和陷阱條件時執行的代碼。如果總的處理器時間較長,請使用此計數器確定導致 CPU 利用率很高的進程。 |
Process |
Handle Count |
顯示此進程當前開啟的控制代碼的總數。此數字是此進程中的每個線程當前開啟的控制代碼總數。特定進程中控制代碼計數的增加可能是發生控制代碼泄漏的錯誤進程的癥狀,這將導致伺服器上發生效能問題。此問題並不一定會出現,但是在一段時間內對其進行監視以確定是否發生控制代碼泄漏十分重要。 |
Process |
Thread Count |
這個進程中正在活動的線程數目。指令是在處理器中基本的執行單位,線程是指執行指令的對象。每個啟動並執行進程至少有一個線程。 |
SQLServer:General Statistics |
User Connections |
顯示sqlserver目前串連的數量,而不是使用者數。如果該計數器超過255,那麼你需要將sqlserver的"Maximum Worker Threads" 的配置值設定得比預設值255高。如果串連的數量超過可用的線程數,那麼sqlserver將共用線程,這樣會影響效能。"Maximum Worker Threads"需要設定得比你伺服器曾經達到的最大串連數更高。 |
SQLServer:Locks |
Number of Deadlocks/sec |
死結的數量/秒,死結對應用程式的延展性非常有害,並且會導致惡劣的使用者體驗。該計數器的值必須為0。 |
LogicalDisk |
% Free Space |
% Free Space 是所選邏輯磁碟機上總計可用空間所佔的百分比。 |
PhysicalDisk |
Disk Read Bytes/sec |
指在讀取操作時從磁碟上傳送位元組的速率。 |
PhysicalDisk |
Disk Write Bytes/sec |
指在寫入操作時傳送到磁碟上的位元組速度。 |
預設狀況下,以下兩個計數器的開關是關著的,需要配置下%WINDIR%\microsoft.net\Framework64\v2.0.50727\CONFIG\machine.config如下開關的(32和64位作業系統的路徑也有不同),否則資料擷取不到。
.NET Data Provider for Oracle |
NumberOfFreeConnections |
.NET Data Provider for SqlServer |
NumberOfFreeConnections |
增加配置,並重啟相應的進程(重啟服務,或者是重啟IIS等)
<system.diagnostics>
<switches>
<add name="ConnectionPoolPerformanceCounterDetail"value="4"/>
</switches>
</system.diagnostics>
用C#採集計數器的資料:
雖然Windows內建了perfmon工具,並可以產生報告以及以各種方式查看過去的效能資料,但是有時候我們還是定義自己的一些曲線或者報表,那麼就需要將效能監控器的資料收集起來,C#提供了PerformanceCounterCategory(效能物件),PerformanceCounter(效能計數器組件)兩個類,提供了操作效能監控器的一些方法,這樣我們就能把資料讀取出來儲存到資料庫中或者檔案中,可用來隨意產生一些曲線或報表,或者警示Mail等。。。
範例程式碼:
using System;
using System.Diagnostics;
using System.Threading;
namespace TestApplication
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine(GetPerfCount("Process", "% Processor Time", "_Total"));
Console.WriteLine(GetPerfCount(".NET CLR Memory", "# Bytes inall Heaps", "_Global_"));
Console.WriteLine(GetPerfCount("SQLServer:GeneralStatistics", "UserConnections"));
Console.Read();
}
/// <summary>
/// 擷取計數器樣本並為其返回計算所得值--有執行個體的計數器(對於大多數的計數器)
/// </summary>
/// <param name="categoryName"></param>
/// <param name="counterName"></param>
/// <param name="instance"></param>
/// <returns></returns>
public static float GetPerfCount(string categoryName, string counterName, string instance)
{
PerformanceCountercounter = new PerformanceCounter
{
CategoryName =categoryName,
CounterName =counterName,
InstanceName = instance,
MachineName = ".",
ReadOnly = true
};
counter.NextValue();
Thread.Sleep(200);
try
{
if (counter != null)
{
return counter.NextValue();
}
}
catch (Exception)
{
return -2f;
}
return -1f;
}
/// <summary>
/// 擷取計數器樣本並為其返回計算所得值--無執行個體的計數器
/// 比如categoryName=SQLServer:General Statistics,counterName=User Connections
/// </summary>
/// <param name="categoryName"></param>
/// <param name="counterName"></param>
/// <returns></returns>
public static float GetPerfCount(string categoryName, string counterName)
{
PerformanceCountercounter = new PerformanceCounter
{
CategoryName =categoryName,
CounterName =counterName
};
counter.NextValue();
Thread.Sleep(200);
try
{
if (counter != null)
{
return counter.NextValue();
}
}
catch (Exception)
{
return -2f;
}
return -1f;
}
}
}