Сервер тормозит. Приложения падают. Пользователи орут. Знакомо?
В 70% случаев проблема в памяти. Но Windows умеет врать: диспетчер задач показывает 60% использования, а сервер уже задыхается.
Эта шпаргалка — для тех, кто устал гадать. Только рабочие команды, реальные метрики и способы быстро найти, кто жрёт память на проде.
Сохраните её — она понадобится в 3 часа ночи, когда мониторинг снова соврёт.
Когда это использовать
Реальные кейсы из практики:
- Сервер начал свопить, хотя RAM свободна на 40%
- IIS падает с Out of Memory, а Task Manager показывает норму
- SQL Server тормозит после обновления
- RDP сессии виснут при входе
- Приложение медленно работает, но метрики «в зелёной зоне»
- После перезагрузки всё ОК, через день — опять беда
Типовые ошибки новичков:
- Смотрят только на «доступную память» в Task Manager
- Игнорируют Committed Memory и Page File
- Не проверяют утечки памяти в конкретных процессах
- Забывают про Memory Compression
- Не анализируют Pool Memory (kernel/drivers)
Быстрый старт (если сервер уже горит)
5 команд для диагностики прямо сейчас:
1. Открыть PowerShell от администратора
2. Проверить Committed Memory:
Get-Counter '\Memory\% Committed Bytes In Use'
Если больше 90% — проблема есть.
3. Найти процессы-пожиратели:
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 10 Name, @{Name="Memory(MB)";Expression={[math]::round($_.WorkingSet / 1MB, 2)}}
4. Проверить Page File usage:
Get-WmiObject Win32_PageFileUsage | Select-Object Name, @{Name="Size(MB)";Expression={$_.AllocatedBaseSize}}, @{Name="Used(MB)";Expression={$_.CurrentUsage}}
5. Посмотреть Available Memory:
(Get-Counter '\Memory\Available MBytes').CounterSamples.CookedValue
Если меньше 10% от общей RAM — сервер задыхается.
Основные метрики и команды
1. Committed Memory — главный индикатор
Что это: сколько памяти обещано процессам (RAM + Page File).
Почему важно: Windows может выделить больше, чем есть физически. Когда Committed > RAM — начинается свопинг и всё тормозит.
# Текущее использование Committed Memory Get-Counter '\Memory\Committed Bytes' | Select-Object -ExpandProperty CounterSamples | Select-Object CookedValue # Лимит Committed Memory Get-Counter '\Memory\Commit Limit' | Select-Object -ExpandProperty CounterSamples | Select-Object CookedValue # Процент использования Get-Counter '\Memory\% Committed Bytes In Use' | Select-Object -ExpandProperty CounterSamples | Select-Object CookedValue
Критические значения:
- До 80% — норма
- 80-90% — начинаются проблемы
- Больше 90% — сервер на грани
2. Available Memory vs Free Memory
Ошибка №1: путать Available и Free.
Free — совсем пустая память (обычно мало, это нормально).
Available — память, которую Windows может быстро освободить для новых процессов (Free + Standby cache).
# Available Memory (главная метрика)
Get-Counter '\Memory\Available MBytes'
# Free Memory (второстепенная)
Get-WmiObject Win32_OperatingSystem | Select-Object @{Name="FreePhysicalMemory(MB)";Expression={[math]::round($_.FreePhysicalMemory / 1KB, 2)}}
# Total Physical Memory
Get-WmiObject Win32_ComputerSystem | Select-Object @{Name="TotalPhysicalMemory(GB)";Expression={[math]::round($_.TotalPhysicalMemory / 1GB, 2)}}
Правило: если Available Memory < 5% от Total RAM — памяти не хватает.
3. Page File (файл подкачки) — индикатор беды
Если Windows активно пишет в Page File — RAM закончилась.
# Использование Page File Get-Counter '\Paging File(_Total)\% Usage' # Частота обращений к диску из-за подкачки Get-Counter '\Memory\Pages/sec' # Статистика Page File Get-WmiObject Win32_PageFileUsage | Format-List *
Критические значения Pages/sec:
- 0-10 — норма
- 10-50 — начинается свопинг
- Больше 50 — сервер умирает
Если Pages/sec постоянно > 20 и растёт — добавляйте RAM.
4. Pool Memory (Non-Paged и Paged Pool)
Что это: память для ядра Windows и драйверов.
Почему важно: утечки в Pool Memory убивают сервер, даже если RAM свободна.
# Non-Paged Pool (не может быть выгружена в Page File) Get-Counter '\Memory\Pool Nonpaged Bytes' # Paged Pool (может быть выгружена) Get-Counter '\Memory\Pool Paged Bytes' # Проверка лимитов Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management" | Select-Object PoolUsageMaximum, PagedPoolSize, NonPagedPoolSize
Признаки утечки в Pool:
- Non-Paged Pool растёт и не падает
- Ошибки «insufficient system resources»
- Синие экраны смерти (BSOD) с кодами, связанными с pool memory
5. Memory Compression (Windows Server 2016+)
Windows сжимает старые страницы памяти вместо выгрузки в Page File.
# Сжатая память
Get-Counter '\Memory\Compressed Pages in Cache'
# Процесс System с высоким использованием = компрессия работает
Get-Process System | Select-Object Name, @{Name="Memory(MB)";Expression={[math]::round($_.WorkingSet / 1MB, 2)}}
Если процесс System жрёт 500+ MB — включена компрессия, памяти не хватает.
6. Топ процессов по использованию памяти
Классический способ:
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 15 Name, Id, @{Name="Memory(MB)";Expression={[math]::round($_.WorkingSet / 1MB, 2)}}
С Private Bytes (более точная метрика):
Get-Counter "\Process(*)\Private Bytes" | Select-Object -ExpandProperty CounterSamples | Sort-Object CookedValue -Descending | Select-Object -First 15 InstanceName, @{Name="Memory(MB)";Expression={[math]::round($_.CookedValue / 1MB, 2)}}
С Handle Count (часто коррелирует с утечками):
Get-Process | Sort-Object Handles -Descending | Select-Object -First 15 Name, Handles, @{Name="Memory(MB)";Expression={[math]::round($_.WorkingSet / 1MB, 2)}}
7. SQL Server — отдельная история
SQL Server может забрать всю память и не отдавать.
# Проверка SQL Server memory usage
Get-Process sqlservr | Select-Object @{Name="Memory(GB)";Expression={[math]::round($_.WorkingSet / 1GB, 2)}}
Проверить настройки Max Server Memory в SQL:
-- В SQL Server Management Studio EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'max server memory';
Если Max Server Memory не настроена — SQL заберёт всё.
8. Утечки памяти — как найти
Мониторинг процесса в реальном времени:
# Запись использования памяти каждые 5 секунд
while ($true) {
Get-Process | Where-Object {$_.Name -eq "w3wp"} | Select-Object Name, @{Name="Memory(MB)";Expression={[math]::round($_.WorkingSet / 1MB, 2)}}, @{Name="Time";Expression={(Get-Date).ToString("HH:mm:ss")}}
Start-Sleep -Seconds 5
}
Если память растёт и не падает — утечка есть.
Dump процесса для анализа:
# Установить ProcDump (Sysinternals) # Сделать dump процесса .\procdump.exe -ma <PID> C:\dumps\process.dmp
Частые ошибки и подводные камни
Ошибка 1: «У меня 40% памяти свободно, всё ОК»
Почему ошибка: Task Manager показывает Physical Memory Usage, а не Committed Memory.
Как проверить правильно:
Get-Counter '\Memory\% Committed Bytes In Use'
Если больше 85% — проблема есть, даже если Physical Memory в норме.
Ошибка 2: «Page File не используется, значит, RAM хватает»
Почему ошибка: Windows может использовать Memory Compression вместо Page File.
Проверить компрессию:
Get-Counter '\Memory\Compressed Pages in Cache'
Если значение большое (сотни тысяч страниц) — памяти не хватает.
Ошибка 3: «Перезагрузил — всё заработало»
Почему ошибка: утечка памяти никуда не делась, просто сбросилась.
Решение: найти процесс с утечкой и исправить/обновить приложение.
Ошибка 4: Игнорирование Standby Cache
Standby Cache — память, занятая файловым кешем, но доступная для приложений.
# Очистить Standby Cache (аварийный способ)
# Требует RAMMap от Sysinternals или:
Write-Host "Clearing standby cache..."
$code = @"
using System;
using System.Runtime.InteropServices;
public class MemoryManagement {
[DllImport("kernel32.dll")]
public static extern bool SetProcessWorkingSetSize(IntPtr proc, int min, int max);
public static void Clear() {
GC.Collect();
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
}
"@
Add-Type -TypeDefinition $code
[MemoryManagement]::Clear()
Внимание: это временное решение, не фикс проблемы.
Ошибка 5: Забыли про драйверы и kernel memory leaks
Драйверы могут течь в Non-Paged Pool.
# Проверить Pool Tagging (требует включения в реестре) # Запустить poolmon.exe (из Windows Driver Kit) # Быстрая проверка без poolmon: Get-Counter '\Memory\Pool Nonpaged Bytes' -SampleInterval 5 -MaxSamples 10
Если Non-Paged Pool растёт на сотни MB в час — ищите плохой драйвер.
Полезные хаки
Хак 1: Мониторинг памяти в одну строку
Get-Counter '\Memory\Available MBytes','\Memory\% Committed Bytes In Use','\Memory\Pages/sec' | Select-Object -ExpandProperty CounterSamples | Format-Table Path, CookedValue -AutoSize
Хак 2: Алиас для быстрой диагностики
# Добавить в $PROFILE
function Check-Memory {
Write-Host "=== Memory Status ===" -ForegroundColor Cyan
$availableMB = (Get-Counter '\Memory\Available MBytes').CounterSamples.CookedValue
$committedPercent = (Get-Counter '\Memory\% Committed Bytes In Use').CounterSamples.CookedValue
$pagesPerSec = (Get-Counter '\Memory\Pages/sec').CounterSamples.CookedValue
Write-Host "Available Memory: $([math]::round($availableMB, 0)) MB"
Write-Host "Committed Memory: $([math]::round($committedPercent, 0))%"
Write-Host "Pages/sec: $([math]::round($pagesPerSec, 0))"
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5 Name, @{Name="Memory(MB)";Expression={[math]::round($_.WorkingSet / 1MB, 2)}}
}
Set-Alias cm Check-Memory
Теперь просто набрать: cm
Хак 3: Автоматический alert при нехватке памяти
# Добавить в Task Scheduler, запускать каждые 5 минут
$availableMB = (Get-Counter '\Memory\Available MBytes').CounterSamples.CookedValue
$totalGB = (Get-WmiObject Win32_ComputerSystem).TotalPhysicalMemory / 1GB
$thresholdMB = $totalGB * 1024 * 0.05 # 5% от общей памяти
if ($availableMB -lt $thresholdMB) {
$message = "LOW MEMORY ALERT! Available: $([math]::round($availableMB, 0)) MB"
Write-EventLog -LogName Application -Source "MemoryMonitor" -EventId 1001 -EntryType Warning -Message $message
# Можно добавить отправку email или webhook
}
Хак 4: Export метрик для графиков
# Собрать метрики памяти в CSV (для Grafana, Excel и т.д.)
$counters = @(
'\Memory\Available MBytes',
'\Memory\% Committed Bytes In Use',
'\Memory\Pages/sec',
'\Memory\Pool Nonpaged Bytes',
'\Paging File(_Total)\% Usage'
)
Get-Counter -Counter $counters -SampleInterval 10 -MaxSamples 360 |
Export-Counter -Path "C:\memory_stats.csv" -FileFormat CSV
Хак 5: One-liner для поиска процессов с утечкой памяти
# Запустить, подождать 5 минут, посмотреть, что растёт
$before = Get-Process | Select-Object Name, Id, WorkingSet64
Start-Sleep -Seconds 300
$after = Get-Process | Select-Object Name, Id, WorkingSet64
Compare-Object $before $after -Property Name, Id, WorkingSet64 |
Where-Object {$_.SideIndicator -eq '=>' -and $_.WorkingSet64 -gt 100MB} |
Sort-Object WorkingSet64 -Descending
Проверка и диагностика
Чек-лист: убедиться, что проблема именно в памяти
1. Committed Memory больше 85%?
Get-Counter '\Memory\% Committed Bytes In Use'
2. Available Memory меньше 10% от RAM?
(Get-Counter '\Memory\Available MBytes').CounterSamples.CookedValue
3. Pages/sec регулярно больше 20?
Get-Counter '\Memory\Pages/sec' -SampleInterval 5 -MaxSamples 10
4. Page File активно используется?
Get-Counter '\Paging File(_Total)\% Usage'
5. Есть процесс, который жрёт аномально много памяти?
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 10 Name, @{Name="Memory(MB)";Expression={[math]::round($_.WorkingSet / 1MB, 2)}}
Если на 3+ вопроса «да» — проблема в памяти.
Где смотреть логи
Event Viewer → Windows Logs → System:
- Event ID 2004 — Resource Exhaustion Detector
- Event ID 2020 — Memory resource exhaustion
- Event ID 1000/1001 — Application crashes (часто из-за Out of Memory)
# Найти события нехватки памяти за последние 24 часа
Get-EventLog -LogName System -After (Get-Date).AddHours(-24) |
Where-Object {$_.EventID -eq 2004 -or $_.EventID -eq 2020}
Performance Monitor (perfmon):
- Добавить счётчики: Memory\*, Paging File\*, Process(*)\Private Bytes
- Записать на 1-2 часа в Data Collector Set
- Открыть .blg файл и найти аномалии
Быстрая диагностика через Performance Monitor
# Запустить perfmon с нужными счётчиками
$counters = @(
'\Memory\Available MBytes',
'\Memory\% Committed Bytes In Use',
'\Memory\Pages/sec',
'\Memory\Pool Nonpaged Bytes',
'\Process(_Total)\Working Set',
'\Paging File(_Total)\% Usage'
)
typeperf $counters -si 5 -sc 120 -o "C:\memory_log.csv"
Запустит сбор метрик на 10 минут (120 семплов по 5 секунд).
Краткий чек-лист для админа
Что проверить перед эскалацией проблемы:
- ✅ Committed Memory: должно быть меньше 85%
- ✅ Available Memory: больше 10% от общей RAM
- ✅ Pages/sec: в среднем меньше 20
- ✅ Page File Usage: меньше 50%
- ✅ Pool Non-Paged Bytes: не растёт постоянно
- ✅ Нет процессов с аномальным ростом памяти
- ✅ Event Log без ошибок 2004/2020
Что сохранить для анализа:
- Вывод
Get-Process | Sort WorkingSet -Desc | Select -First 20 - Скриншот Resource Monitor (Memory tab)
- Dump проблемного процесса (procdump.exe -ma PID)
- Perfmon log за 1-2 часа
- События из Event Viewer (Get-EventLog)
Что делать, если памяти точно не хватает:
- 🔹 Краткосрочно: перезагрузка сервиса/сервера
- 🔹 Среднесрочно: найти и исправить утечку памяти
- 🔹 Долгосрочно: добавить RAM или оптимизировать приложения
Резюме
Нехватку памяти на Windows Server легко пропустить, если смотреть не на те метрики.
Главное правило: не верьте Task Manager. Проверяйте Committed Memory, Available Memory и Pages/sec.
Эта шпаргалка спасла не один прод. Сохраните её в закладки — она понадобится в самый неожиданный момент.
Следующая шпаргалка — «Диагностика высокой нагрузки на CPU в Windows Server: команды для копирования». Подпишитесь, чтобы не пропустить.
Если команда не сработала — проверьте, что PowerShell запущен от администратора. Если всё равно не работает — значит, где-то забыли флаг.



