Windows’ta Yüksek CPU Kullanımını Tespit ve Çözme

Bir üretim sunucusunda CPU kullanımının aniden %90’ların üzerine çıktığını görüyorsunuz ve kullanıcılar uygulamanın yavaşladığından şikayet etmeye başlamış. Bu durumda paniğe kapılmak yerine sistematik bir yaklaşım benimsemeniz gerekiyor. Windows’ta yüksek CPU sorunlarını tespit etmek, Linux’a kıyasla biraz farklı bir düşünce yapısı gerektiriyor; ama doğru araçları biliyorsanız, köke inmek düşündüğünüzden çok daha hızlı oluyor.

Bu yazıda gerçek hayatta karşılaştığım senaryolar üzerinden ilerleyeceğim. Sıfırdan başlayıp, sorunu izole edip, kalıcı çözüme ulaşana kadar tüm adımları ele alacağız.

İlk Müdahale: Durumu Hızlıca Anlamak

Alarmı aldığınızda ilk yapmanız gereken şey sunucuya RDP bağlanıp Task Manager’ı açmak değil. Görev yöneticisi güzel bir başlangıç noktası ama yetersiz. Önce şunu sormak lazım: Bu ani bir spike mi, yoksa saatlerdir devam eden bir durum mu?

Eğer RDP bile açılmıyorsa, sunucuya console erişimiyle ya da başka bir makineden PowerShell remoting ile bağlanmayı deneyin:

Enter-PSSession -ComputerName SUNUCU_ADI -Credential (Get-Credential)

Bağlandıktan sonra ilk işim şu komutu çalıştırmak oluyor:

Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, CPU, WorkingSet, Id | Format-Table -AutoSize

Bu komut CPU’yu en çok tüketen ilk 10 prosesi gösteriyor. Ama burada dikkat: CPU sütunu, process’in başladığından bu yana toplam işlemci süresi. Anlık tüketim için biraz farklı bir yaklaşım lazım.

Anlık CPU yüzdesini görmek için şöyle bir döngü kurabilirsiniz:

while ($true) {
    Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 Name, CPU, Id
    Start-Sleep -Seconds 2
    Write-Host "---"
}

Task Manager’ın Ötesi: Process Monitor ve Process Explorer

Standart görev yöneticisi size process adını gösterir ama hangi thread’in ya da hangi DLL’nin soruna yol açtığını göstermez. Sysinternals suite burada devreye giriyor.

Process Explorer ile bir process’e çift tıkladığınızda thread bazında CPU tüketimini görebilirsiniz. Özellikle svchost.exe gibi onlarca servisi barındıran process’lerde bu kritik. Görev yöneticisinde “svchost.exe %40 CPU kullanıyor” görürsünüz ama hangisi olduğunu bilemezsiniz. Process Explorer’da o svchost instance’ına sağ tıklayıp “Properties > Services” sekmesinden içindeki servisleri görebilirsiniz.

Process Monitor ise file system, registry ve network aktivitelerini gerçek zamanlı takip eder. Bir process neden bu kadar CPU yiyor diye bakarken aslında sürekli bir registry key okuyorsa ya da olmayan bir dosyayı tekrar tekrar arıyorsa, bunu sadece Process Monitor ile yakalarsınız.

Sysinternals araçlarını indirmeden doğrudan çalıştırmak için:

\live.sysinternals.comtoolsprocexp.exe

Network erişimi yoksa önceden indirip bir network share’e koymanızı öneririm.

WMI ile Derinlemesine Analiz

Bazen sorun belirli bir process değil, genel sistem davranışıdır. WMI ile çok daha detaylı bilgi çekebilirsiniz:

Get-WmiObject Win32_Processor | Select-Object Name, LoadPercentage, NumberOfCores, NumberOfLogicalProcessors

Birden fazla CPU core’unuz varsa tek bir core’un mu yoksa tüm core’ların mı dolu olduğunu anlamak önemli. Tek bir thread’in deli gibi çalışması, multithread tasarlanmamış eski bir uygulamaya işaret edebilir.

Process bazında daha detaylı WMI sorgusu için:

Get-WmiObject Win32_PerfFormattedData_PerfProc_Process |
    Where-Object { $_.Name -ne "_Total" -and $_.Name -ne "Idle" } |
    Sort-Object PercentProcessorTime -Descending |
    Select-Object -First 10 Name, PercentProcessorTime, IDProcess |
    Format-Table -AutoSize

Bu sorgu anlık CPU yüzdesini verdiği için çok daha güvenilir. Özellikle kısa süreli spike’ları yakalamak için birkaç kez çalıştırıp sonuçları karşılaştırın.

Svchost Karmaşasını Çözmek

Windows sunucularda yüksek CPU’nun en yaygın nedenlerinden biri svchost.exe altındaki servislerdir. Windows Update servisi özellikle bunu çok yapıyor; özellikle eski sunucularda, büyük bir güncelleme paketinden sonra WUAUServ saatlerce CPU’yu tıkayabiliyor.

Svchost process ID’sini alıp içindeki servisleri görmek için:

$svchostProcesses = Get-Process svchost
foreach ($proc in $svchostProcesses) {
    $services = Get-WmiObject -Query "SELECT * FROM Win32_Service WHERE ProcessId = $($proc.Id)"
    if ($services) {
        Write-Host "PID: $($proc.Id) - CPU: $($proc.CPU)"
        $services | ForEach-Object { Write-Host "  -> $($_.Name): $($_.DisplayName)" }
    }
}

Bu scripti çalıştırdığınızda hangi PID altında hangi servislerin çalıştığını açıkça görürsünüz. Yüksek CPU’ya sahip PID’i bulduktan sonra ilgili servisi izole edebilirsiniz.

Windows Update kaynaklı bir sorun şüphesiniz varsa şöyle kontrol edebilirsiniz:

Get-Service wuauserv | Select-Object Status, StartType
Stop-Service wuauserv
# CPU düşüyor mu kontrol edin
Start-Service wuauserv

Performance Monitor ile Tarihsel Analiz

Sorun sürekli yaşanıyorsa anlık araçlar yetmez; tarihsel veri toplamanız gerekir. Windows’un built-in Performance Monitor (perfmon) aracı bu iş için biçilmiş kaftan.

Komut satırından bir veri toplama görevi oluşturmak için:

logman create counter CPUAnalysis -c "Processor(_Total)% Processor Time" "Process(*)% Processor Time" -si 5 -f csv -o C:PerfLogsCPUAnalysis.csv -rf 01:00:00
logman start CPUAnalysis

Bu komut her 5 saniyede bir tüm process’lerin CPU kullanımını 1 saat boyunca CSV dosyasına kaydeder. Sonuçları analiz etmek için:

$data = Import-Csv "C:PerfLogsCPUAnalysis.csv"
$data | Select-Object -First 5 | Format-List

Üretimde bu tür bir loglama sürekli açık olması gereken bir şey. Sorun oluştuğunda “keşke data toplasaydım” demek yerine, önceden kurulu bir izleme altyapısı hayat kurtarıyor.

Gerçek Dünya Senaryosu: IIS ve .NET Uygulaması

Geçen yıl bir e-ticaret sitesinin sunucusunda tam gün boyunca %85-95 arasında gidip gelen CPU sorunu vardı. Uygulama IIS üzerinde çalışan bir .NET uygulamasıydı. İlk bakışta w3wp.exe suçluydu.

Ama hangi application pool? Birden fazla pool vardı:

C:WindowsSystem32inetsrvappcmd.exe list wp

Bu komut çalışan worker process’leri ve bağlı oldukları application pool’ları gösterir. Yüksek CPU kullanan w3wp.exe’nin PID’ini alıp buradan eşleştirince “ProductSearch” adlı pool’u suçlu olarak tespit ettik.

Sonraki adım o pool’daki uygulamanın memory dump’ını almaktı:

procdump -ma -p <PID> C:Dumpsw3wp_dump.dmp

Procdump da Sysinternals ailesi. Dump’ı WinDbg ile açtığımızda bir veritabanı sorgusu döngüde takılmış ve her istek için yüzlerce kez çalışıyordu. Index eksikliği kaynaklı bir ORM problemi. Çözüm basitti: Doğru index eklendi, CPU anında normale döndü.

Scheduled Tasks ve Gizli Süreçler

Yüksek CPU spike’larını araştırırken scheduled task’ları gözden geçirmek çok önemli. Gece çalışması gereken bir backup job’ı veya antivirus scan’i gündüz çalışıyorsa farkında olmadan CPU tüketebilir.

Çalışan scheduled task’ları listelemek için:

Get-ScheduledTask | Where-Object { $_.State -eq "Running" } | Select-Object TaskName, TaskPath, State

Son çalışma zamanlarını ve durumlarını görmek için:

Get-ScheduledTask | Get-ScheduledTaskInfo | Where-Object { $_.LastRunTime -gt (Get-Date).AddHours(-2) } | Select-Object TaskName, LastRunTime, LastTaskResult | Format-Table -AutoSize

Bir keresinde bir sunucuda Windows Defender’ın tam tarama görevi her gün öğle vakti çalışıyor ve 2 saat boyunca CPU’yu %70’in üzerinde tutuyordu. Kimse bunu kasıtlı ayarlamamıştı, default schedule öyleydi. Tarama saatini gece 02:00’ye almak sorunu tamamen çözdü.

Antivirus Muafiyet Listesi

Windows sunucularda antivirus yazılımları inanılmaz derecede fazla CPU tüketebilir, özellikle real-time protection aktifken yoğun disk I/O olan uygulamalar çalışıyorsa. SQL Server data dosyaları, Exchange veritabanları veya IIS log klasörleri gibi yüksek aktiviteli dizinlerin antivirus taramasından muaf tutulması hem performansı artırır hem de false positive riskini azaltır.

Defender üzerinden muafiyet eklemek için PowerShell:

Add-MpPreference -ExclusionPath "C:Program FilesMicrosoft SQL Server"
Add-MpPreference -ExclusionPath "D:SQLData"
Add-MpPreference -ExclusionProcess "sqlservr.exe"
Add-MpPreference -ExclusionProcess "w3wp.exe"
Get-MpPreference | Select-Object ExclusionPath, ExclusionProcess

Tabi muafiyet listesini genişletirken güvenlik riskini de göz önünde bulundurmak gerekiyor. Kör bir şekilde her şeyi muaf tutmak değil, bilinçli seçimler yapmak önemli.

Event Log’ları Taramak

CPU sorunları çoğunlukla başka semptomlarla birlikte gelir. Event log’larda hata mesajları, crash’ler veya servis restart kayıtları bulabilirsiniz:

Get-EventLog -LogName System -EntryType Error -Newest 50 | Select-Object TimeGenerated, Source, Message | Format-List
Get-EventLog -LogName Application -EntryType Error -Newest 50 | Where-Object { $_.TimeGenerated -gt (Get-Date).AddHours(-4) } | Select-Object TimeGenerated, Source, EventID, Message | Format-List

Özellikle DCOM hataları, .NET runtime exception’ları ve servis crash mesajları CPU problemiyle doğrudan bağlantılı olabilir. EventID 7034 bir servisin beklenmedik şekilde kapandığını gösterir; bu servis sürekli restart ediliyorsa her restart döngüsünde CPU spike yaratır.

Kalıcı Çözüm: Resource Monitor ve Threshold Alerting

Sorunu tespit edip çözdükten sonra asıl mesele tekrar yaşanmaması. Windows Resource Monitor gerçek zamanlı detaylı analiz için harika, ama otomatik uyarı için yeterli değil.

Task Scheduler ile basit bir CPU izleme scripti kurmak:

$threshold = 85
$cpuUsage = (Get-WmiObject Win32_Processor | Measure-Object -Property LoadPercentage -Average).Average

if ($cpuUsage -gt $threshold) {
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $topProcesses = Get-WmiObject Win32_PerfFormattedData_PerfProc_Process |
        Where-Object { $_.Name -ne "_Total" -and $_.Name -ne "Idle" } |
        Sort-Object PercentProcessorTime -Descending |
        Select-Object -First 5 Name, PercentProcessorTime

    $body = "CPU Uyarisi: $timestamp`n"
    $body += "Mevcut CPU Kullanimi: $cpuUsage%`n`n"
    $body += "En fazla CPU kullanan prosesler:`n"
    foreach ($proc in $topProcesses) {
        $body += "  - $($proc.Name): $($proc.PercentProcessorTime)%`n"
    }

    Send-MailMessage -To "[email protected]" -From "[email protected]" -Subject "UYARI: Yuksek CPU - $env:COMPUTERNAME" -Body $body -SmtpServer "smtp.sirket.com"

    Add-Content -Path "C:LogsCPUAlerts.log" -Value $body
}

Bu scripti her 5 dakikada bir çalışan bir scheduled task olarak eklerseniz, kriz anında email alırsınız ve log dosyasında ne olduğunu görebilirsiniz.

Daha profesyonel bir izleme altyapısı istiyorsanız PRTG, Zabbix veya Prometheus+Grafana kombinasyonu düşünebilirsiniz. Ama küçük ortamlar için yukarıdaki script gayet işe yarıyor.

Kernel vs User Space: Hangisi Suçlu?

Görev yöneticisinde CPU sütununa dikkatli bakın. Eğer CPU kullanımı yüksek ama process listesinde bunu açıklayan bir şey göremiyorsanız, sorun kernel modunda olabilir.

Performance Monitor’da şu counter’ları ekleyin:

  • Processor(_Total)% Privileged Time: Kernel mode’da geçen süre
  • Processor(_Total)% User Time: User mode’da geçen süre
  • Processor(_Total)% Interrupt Time: Donanım interrupt’larına harcanan süre

Eğer % Interrupt Time yüksekse sorun büyük ihtimalle bir donanım sürücüsüdür, özellikle NIC veya storage controller driver’ı. Bu durumda driver güncellemesi ya da değiştirilmesi gerekebilir.

% Privileged Time yüksek ama % Interrupt Time normalse, kernel mode’da çalışan bir yazılım bileşeni (antivirus kernel driver’ı gibi) şüphelidir.

Sonuç

Windows’ta yüksek CPU sorunları bazen birkaç dakikada çözülür, bazen saatlerinizi alır. Fark yaratan şey paniklemek yerine sistematik ilerlemek. İlk adımda hangi process’in suçlu olduğunu tespit edin, sonra neden o process’in bu kadar CPU tükettiğini anlayın.

Unutmayın: Yüksek CPU her zaman bir bug işareti değildir. Meşru bir iş yükü de CPU’yu yüksek tutabilir. Ama eğer “normal” bir iş yükünde anormal CPU tüketimi görüyorsanız, bu genellikle kod kalitesi sorunu (kötü query, sonsuz döngü, bellek sızıntısı kaynaklı GC baskısı), yanlış yapılandırma (antivirus, zamanlanmış görev çakışması) veya donanım/driver sorunundan birini işaret eder.

En güçlü araçlarınız: Sysinternals suite, PowerShell WMI sorguları, Performance Monitor ve iyi ayarlanmış bir log stratejisi. Bu üçünü birlikte kullandığınızda Windows sunucularda neredeyse hiçbir CPU problemi sizi uzun süre oyalamaz.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir