Как определить, что Windows серверу не хватает памяти: шпаргалка IT-инженера с примерами

Шпаргалка IT-инженера: как определить нехватку памяти на Windows Server. Готовые команды PowerShell, метрики, диагностика утечек. Available Memory, Committed Memory, Pages/sec — проверка за 2 минуты. Сохраните для продакшена.

Сервер тормозит. Приложения падают. Пользователи орут. Знакомо?

В 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 &#039;\Paging File(_Total)\% Usage&#039;

# Частота обращений к диску из-за подкачки
Get-Counter &#039;\Memory\Pages/sec&#039;

# Статистика 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 &#039;\Memory\Pool Nonpaged Bytes&#039;

# Paged Pool (может быть выгружена)
Get-Counter &#039;\Memory\Pool Paged Bytes&#039;

# Проверка лимитов
Get-ItemProperty &quot;HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management&quot; | 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 &#039;\Memory\Compressed Pages in Cache&#039;

# Процесс System с высоким использованием = компрессия работает
Get-Process System | Select-Object Name, @{Name=&quot;Memory(MB)&quot;;Expression={[math]::round($_.WorkingSet / 1MB, 2)}}

Если процесс System жрёт 500+ MB — включена компрессия, памяти не хватает.

6. Топ процессов по использованию памяти

Классический способ:

Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 15 Name, Id, @{Name=&quot;Memory(MB)&quot;;Expression={[math]::round($_.WorkingSet / 1MB, 2)}}

С Private Bytes (более точная метрика):

Get-Counter &quot;\Process(*)\Private Bytes&quot; | Select-Object -ExpandProperty CounterSamples | Sort-Object CookedValue -Descending | Select-Object -First 15 InstanceName, @{Name=&quot;Memory(MB)&quot;;Expression={[math]::round($_.CookedValue / 1MB, 2)}}

С Handle Count (часто коррелирует с утечками):

Get-Process | Sort-Object Handles -Descending | Select-Object -First 15 Name, Handles, @{Name=&quot;Memory(MB)&quot;;Expression={[math]::round($_.WorkingSet / 1MB, 2)}}

7. SQL Server — отдельная история

SQL Server может забрать всю память и не отдавать.

# Проверка SQL Server memory usage
Get-Process sqlservr | Select-Object @{Name=&quot;Memory(GB)&quot;;Expression={[math]::round($_.WorkingSet / 1GB, 2)}}

Проверить настройки Max Server Memory в SQL:

-- В SQL Server Management Studio
EXEC sp_configure &#039;show advanced options&#039;, 1;
RECONFIGURE;
EXEC sp_configure &#039;max server memory&#039;;

Если Max Server Memory не настроена — SQL заберёт всё.

8. Утечки памяти — как найти

Мониторинг процесса в реальном времени:

# Запись использования памяти каждые 5 секунд
while ($true) {
    Get-Process | Where-Object {$_.Name -eq &quot;w3wp&quot;} | Select-Object Name, @{Name=&quot;Memory(MB)&quot;;Expression={[math]::round($_.WorkingSet / 1MB, 2)}}, @{Name=&quot;Time&quot;;Expression={(Get-Date).ToString(&quot;HH:mm:ss&quot;)}}
    Start-Sleep -Seconds 5
}

Если память растёт и не падает — утечка есть.

Dump процесса для анализа:

# Установить ProcDump (Sysinternals)
# Сделать dump процесса
.\procdump.exe -ma &lt;PID&gt; C:\dumps\process.dmp

Частые ошибки и подводные камни

Ошибка 1: «У меня 40% памяти свободно, всё ОК»

Почему ошибка: Task Manager показывает Physical Memory Usage, а не Committed Memory.

Как проверить правильно:

Get-Counter &#039;\Memory\% Committed Bytes In Use&#039;

Если больше 85% — проблема есть, даже если Physical Memory в норме.

Ошибка 2: «Page File не используется, значит, RAM хватает»

Почему ошибка: Windows может использовать Memory Compression вместо Page File.

Проверить компрессию:

Get-Counter &#039;\Memory\Compressed Pages in Cache&#039;

Если значение большое (сотни тысяч страниц) — памяти не хватает.

Ошибка 3: «Перезагрузил — всё заработало»

Почему ошибка: утечка памяти никуда не делась, просто сбросилась.

Решение: найти процесс с утечкой и исправить/обновить приложение.

Ошибка 4: Игнорирование Standby Cache

Standby Cache — память, занятая файловым кешем, но доступная для приложений.

# Очистить Standby Cache (аварийный способ)
# Требует RAMMap от Sysinternals или:
Write-Host &quot;Clearing standby cache...&quot;
$code = @&quot;
using System;
using System.Runtime.InteropServices;
public class MemoryManagement {
    [DllImport(&quot;kernel32.dll&quot;)]
    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);
    }
}
&quot;@
Add-Type -TypeDefinition $code
[MemoryManagement]::Clear()

Внимание: это временное решение, не фикс проблемы.

Ошибка 5: Забыли про драйверы и kernel memory leaks

Драйверы могут течь в Non-Paged Pool.

# Проверить Pool Tagging (требует включения в реестре)
# Запустить poolmon.exe (из Windows Driver Kit)

# Быстрая проверка без poolmon:
Get-Counter &#039;\Memory\Pool Nonpaged Bytes&#039; -SampleInterval 5 -MaxSamples 10

Если Non-Paged Pool растёт на сотни MB в час — ищите плохой драйвер.

Полезные хаки

Хак 1: Мониторинг памяти в одну строку

Get-Counter &#039;\Memory\Available MBytes&#039;,&#039;\Memory\% Committed Bytes In Use&#039;,&#039;\Memory\Pages/sec&#039; | Select-Object -ExpandProperty CounterSamples | Format-Table Path, CookedValue -AutoSize

Хак 2: Алиас для быстрой диагностики

# Добавить в $PROFILE
function Check-Memory {
    Write-Host &quot;=== Memory Status ===&quot; -ForegroundColor Cyan
    $availableMB = (Get-Counter &#039;\Memory\Available MBytes&#039;).CounterSamples.CookedValue
    $committedPercent = (Get-Counter &#039;\Memory\% Committed Bytes In Use&#039;).CounterSamples.CookedValue
    $pagesPerSec = (Get-Counter &#039;\Memory\Pages/sec&#039;).CounterSamples.CookedValue
    
    Write-Host &quot;Available Memory: $([math]::round($availableMB, 0)) MB&quot;
    Write-Host &quot;Committed Memory: $([math]::round($committedPercent, 0))%&quot;
    Write-Host &quot;Pages/sec: $([math]::round($pagesPerSec, 0))&quot;
    
    Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5 Name, @{Name=&quot;Memory(MB)&quot;;Expression={[math]::round($_.WorkingSet / 1MB, 2)}}
}

Set-Alias cm Check-Memory

Теперь просто набрать: cm

Хак 3: Автоматический alert при нехватке памяти

# Добавить в Task Scheduler, запускать каждые 5 минут
$availableMB = (Get-Counter &#039;\Memory\Available MBytes&#039;).CounterSamples.CookedValue
$totalGB = (Get-WmiObject Win32_ComputerSystem).TotalPhysicalMemory / 1GB
$thresholdMB = $totalGB * 1024 * 0.05  # 5% от общей памяти

if ($availableMB -lt $thresholdMB) {
    $message = &quot;LOW MEMORY ALERT! Available: $([math]::round($availableMB, 0)) MB&quot;
    Write-EventLog -LogName Application -Source &quot;MemoryMonitor&quot; -EventId 1001 -EntryType Warning -Message $message
    # Можно добавить отправку email или webhook
}

Хак 4: Export метрик для графиков

# Собрать метрики памяти в CSV (для Grafana, Excel и т.д.)
$counters = @(
    &#039;\Memory\Available MBytes&#039;,
    &#039;\Memory\% Committed Bytes In Use&#039;,
    &#039;\Memory\Pages/sec&#039;,
    &#039;\Memory\Pool Nonpaged Bytes&#039;,
    &#039;\Paging File(_Total)\% Usage&#039;
)

Get-Counter -Counter $counters -SampleInterval 10 -MaxSamples 360 | 
    Export-Counter -Path &quot;C:\memory_stats.csv&quot; -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 &#039;=&gt;&#039; -and $_.WorkingSet64 -gt 100MB} | 
    Sort-Object WorkingSet64 -Descending

Проверка и диагностика

Чек-лист: убедиться, что проблема именно в памяти

1. Committed Memory больше 85%?

Get-Counter &#039;\Memory\% Committed Bytes In Use&#039;

2. Available Memory меньше 10% от RAM?

(Get-Counter &#039;\Memory\Available MBytes&#039;).CounterSamples.CookedValue

3. Pages/sec регулярно больше 20?

Get-Counter &#039;\Memory\Pages/sec&#039; -SampleInterval 5 -MaxSamples 10

4. Page File активно используется?

Get-Counter &#039;\Paging File(_Total)\% Usage&#039;

5. Есть процесс, который жрёт аномально много памяти?

Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 10 Name, @{Name=&quot;Memory(MB)&quot;;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 = @(
    &#039;\Memory\Available MBytes&#039;,
    &#039;\Memory\% Committed Bytes In Use&#039;,
    &#039;\Memory\Pages/sec&#039;,
    &#039;\Memory\Pool Nonpaged Bytes&#039;,
    &#039;\Process(_Total)\Working Set&#039;,
    &#039;\Paging File(_Total)\% Usage&#039;
)

typeperf $counters -si 5 -sc 120 -o &quot;C:\memory_log.csv&quot;

Запустит сбор метрик на 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 запущен от администратора. Если всё равно не работает — значит, где-то забыли флаг.

over_dude
Author: over_dude

Поделитесь:

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх