АйТи Фреш
Главная / Статьи / 1С и базы данных
1С и базы данных

Ограничил max server memory, а sqlservr.exe съел больше: какая память не входит в лимит

Автор: Семёнов Евгений Сергеевич, директор ООО «АйТи-Фреш» · · ~25 мин чтения
Ограничил max server memory, а sqlservr.exe съел больше: какая память не входит в лимит
Иллюстрация к статье «Ограничил max server memory, а sqlservr.exe съел больше: какая память не входит в лимит».

Классическая паника сисадмина: в свойствах инстанса выставлено 36 ГБ, а в диспетчере задач у sqlservr.exe почти 41 ГБ. Первая мысль — «утечка, надо перезагружать». На самом деле вы сравниваете две разные величины: лимит менеджера памяти движка и коммит всего процесса Windows. Разбираю, что именно ограничивает max server memory, что живёт вне лимита, как посчитать значение для сервера, где на одной машине крутятся и SQL Server, и сервер 1С, и как за пятнадцать минут понять, кто именно съел дельту.

Что вообще ограничивает max server memory

Максимально короткая формулировка: max server memory (MB) ограничивает не процесс sqlservr.exe, а менеджер памяти движка. Всё, что проходит через него — buffer pool, план-кэш и остальные кэши, память компиляции, memory grants на сортировки и хэши, менеджер блокировок, память CLR — считается внутри лимита. Правило простое до неприличия: если потребитель виден в sys.dm_os_memory_clerks, он считается внутри лимита. Если не виден — значит, вы его лимитом не контролируете.

Начиная с SQL Server 2012 в лимит утянули то, что раньше было снаружи: multi-page allocations (запросы больше 8 КБ) и CLR-аллокации свели в единый «any size» page allocator. Поэтому старые расчёты «оставьте четверть под Mem-To-Leave» с тех пор устарели, а в 2025-й версии ничего принципиально не поменялось: архитектура памяти та же, что в 2012–2022. Что действительно поменялось в SQL Server 2025 (17.x) — редакция Standard теперь тянет до 256 ГБ вместо прежних 128 ГБ. Для небольших компаний это скорее запас на вырост: сервер на 32–64 ГБ в потолок Standard не упирался и раньше, а вот при переезде на железо со 192 ГБ расчёт лимита снова становится упражнением в арифметике, а не в «всё равно больше 128 не возьмёт».

Дефолт у настройки — 2 147 483 647 МБ, то есть «бери сколько дадут». Минимально допустимое значение — 128 МБ, и это не шутка: поставьте его случайно, и инстанс может не стартовать, поднимать придётся с ключом -f. С SQL Server 2019 инсталлятор на Windows сам предлагает разумное значение при установке standalone-инстанса, но я всё равно проверяю руками — предложение мастера не знает, что через месяц вы поставите на тот же сервер агент бэкапа и антивирус.

На странице Microsoft о server memory options есть ремарка «The max server memory option only limits the size of the SQL Server buffer pool». Читать её надо в широком смысле: в документации под buffer pool здесь понимаются все аллокации менеджера памяти движка, а таблица в Memory Management Architecture Guide прямо показывает, что с 2012 года в лимит входят и multi-page, и CLR-аллокации. Ориентируйтесь на список memory clerks, а не на одну фразу.
Цифры и версии: Что вообще ограничивает max server memory — схема
Цифры и версии: Что вообще ограничивает max server memory. Открыть схему в полном размере

Что живёт снаружи лимита — с цифрами

Первый и самый предсказуемый потребитель вне лимита — стеки рабочих потоков. Для x64 SQL Server на x64 Windows размер стека потока — 2048 КБ, то есть ровно 2 МБ на поток. Число потоков считается автоматически, когда max worker threads = 0, по формуле «512 + (логических CPU − 4) × 16» для 64-битной платформы (для 5–64 логических CPU, начиная с SQL Server 2016 SP2 и 2017): 512 потоков до 4 ядер, 576 на 8, 704 на 16, 960 на 32, 1472 на 64. На 32-ядерном сервере это 960 × 2 МБ ≈ 1,9 ГБ, которые движок вообще не считает своими. Не катастрофа, но при расчёте лимита их надо вычесть явно.

Второй пласт — прямые аллокации Windows (Direct Windows Allocations). Это память, которую внутри процесса sqlservr.exe запрашивают модули, к движку отношения не имеющие: DLL расширенных хранимых процедур, OLE DB провайдеры линкованных серверов, объекты OLE Automation через sp_OACreate, а также — и вот это отдельная боль — драйверы фильтрации антивирусов и агентов мониторинга, которые инжектят свои библиотеки в процесс. Менеджер памяти движка о них ничего не знает, ограничить их через max server memory нельзя в принципе.

Третье — буферы резервного копирования. Если вы гоняете нативный BACKUP DATABASE с ручными BUFFERCOUNT и MAXTRANSFERSIZE, эти буферы выделяются вне лимита, и на большой базе с агрессивными настройками они дают ощутимый всплеск. У меня был случай, когда ночной джоб с BUFFERCOUNT = 200 и MAXTRANSFERSIZE = 4194304 добавлял почти 800 МБ поверх лимита ровно на время бэкапа — и админ клиента честно ловил это в мониторинге как «утечку в 03:15».

Отдельно стоит легальное превышение лимита самим движком. Начиная с 2012 версии, если Total Server Memory уже дошёл до Target и приходит запрос на multi-page аллокацию, а непрерывной свободной памяти из-за фрагментации нет, SQL Server может выполнить over-commit вместо отказа. Дальше Resource Monitor подтягивает потребление обратно. Ловится это на больших columnstore-запросах, перестроении columnstore-индексов, батч-режиме и крупных memory grants. В SQL Server 2019 ускорить уборку можно было трейс-флагом 8121, а начиная с SQL Server 2022 это поведение включено по умолчанию, и флаг ничего не делает.

Не гонитесь за копейками. Стеки потоков и буферы бэкапа — это единицы гигабайт и они предсказуемы. Реальные аварии почти всегда дают линкованный сервер в режиме inprocess или агрессивный EDR, а не арифметика стеков.
Ограничил max server memory, а sqlservr.exe съел больше: какая память не входит в лимит — схема
Схема к статье. Открыть схему в полном размере

Разбор из практики: турагентство «ТурГавань», 48 ГБ на двоих — SQL и 1С

Турагентство «ТурГавань» — 25 рабочих мест, менеджеры по продажам туров, бухгалтерия и пара человек в back-office. Весь учёт живёт на одном сервере: Windows Server 2022, SQL Server 2022 Standard, рядом на той же машине — сервер 1С:Предприятие 8.3 с базами бухгалтерии и управленческого учёта, плюс отдельная база системы бронирования туров на том же инстансе. Железо: 8 физических ядер (16 логических), 48 ГБ RAM. Жалоба звучала так: «к вечеру 1С виснет, а SQL жрёт больше, чем разрешено». Настроено было max server memory = 36 864 МБ (36 ГБ), в диспетчере задач у sqlservr.exe к концу дня 40–41 ГБ, счётчик Memory\Available MBytes падал до 250–400 МБ, процессы rphost периодически перезапускались кластером 1С, а в логе SQL несколько раз в неделю всплывала ошибка 17890 про то, что значительная часть памяти процесса выгружена на диск.

Первым делом я не трогал лимит, а снял цифры одновременно: приватные байты процесса SQL, Total Server Memory движка, доступную память ОС и — раз сервер 1С живёт на той же машине — суммарное потребление его процессов:

Get-Counter -Counter @(
  '\Process(sqlservr)\Private Bytes',
  '\Process(sqlservr)\Working Set',
  '\Process(rphost*)\Private Bytes',
  '\Process(rmngr)\Private Bytes',
  '\Process(ragent)\Private Bytes',
  '\SQLServer:Memory Manager\Total Server Memory (KB)',
  '\SQLServer:Memory Manager\Target Server Memory (KB)',
  '\Memory\Available MBytes'
) -SampleInterval 5 -MaxSamples 12

Получилось: Private Bytes у sqlservr ≈ 40,6 ГБ, Total Server Memory ≈ 36 ГБ, то есть ровно лимит. Дельта — около 4,5 ГБ, и она вся снаружи движка. Процессы 1С (все rphost плюс rmngr и ragent) в вечерний пик занимали 6–7 ГБ, ОС с файловым кэшем и агентами — ещё около 3 ГБ. Сумма честно не помещалась в 48 ГБ. Дальше смотрим, кто внутри процесса SQL живёт кроме самого движка:

tasklist /M /FI "IMAGENAME eq sqlservr.exe"

И более цивилизованно, из самого SQL:

SELECT name, description, company
FROM sys.dm_os_loaded_modules
WHERE company NOT LIKE 'Microsoft%' OR company IS NULL;

SELECT type, name, pages_kb / 1024 AS pages_mb
FROM sys.dm_os_memory_clerks
WHERE type = 'MEMORYCLERK_HOST';

Нашлось ровно то, что я и ожидал: OLE DB провайдер линкованного сервера, через который ночной и вечерний регламент затягивал выгрузки из базы бронирования в промежуточные таблицы для 1С, и пара библиотек EDR-агента. Линкованный сервер стоял с включённой опцией Allow inprocess, а запрос сверки забирал через него сотни тысяч строк заявок одним махом. Плюс антивирус без единого исключения — сканировал mdf/ldf и файлы бэкапов на лету.

Что сделал. Опцию Allow inprocess у линкованного сервера снял — провайдер поддерживает работу вне процесса, это я предварительно проверил тестовым прогоном регламента; сам запрос сверки разбили на порции по датам. Антивирусу выдал исключения по каталогам данных и по процессу sqlservr.exe. И только после этого пересчитал лимит: 48 ГБ физической минус 4 ГБ на ОС, минус 1,4 ГБ на стеки потоков (704 × 2 МБ), минус 7 ГБ на измеренный пик процессов 1С, минус 2 ГБ запаса на внешние аллокации — получилось 33,6 ГБ, округлил вниз до 32 ГБ = 32 768 МБ. Результат через неделю наблюдений: Available MBytes держится в диапазоне 3–5 ГБ даже в вечерний пик, Private Bytes sqlservr — 33–33,5 ГБ, дельта над лимитом ужалась примерно до 1–1,5 ГБ, ошибка 17890 из лога исчезла, перезапуски rphost прекратились. Никакой утечки не было ни одного дня — была арифметика, в которой забыли про сервер 1С.

Самая частая ошибка в такой ситуации — сразу резать лимит вдвое «чтобы наверняка». Это лечит симптом ценой роста дискового ввода-вывода и падения Page Life Expectancy. Сначала уберите потребителя снаружи движка и учтите соседей по серверу (1С, терминальные сессии), лимит трогайте последним.

Как я считаю max server memory руками

Официальная методика Microsoft звучит так: от всей памяти ОС отнять «размер стека × расчётное число max worker threads», затем отнять 25 % на прочие аллокации вне лимита (буферы бэкапа, DLL расширенных процедур, sp_OA, провайдеры линкованных серверов), остаток и есть значение для одиночного инстанса. Формулировка честная, но сама документация сразу оговаривается, что это грубое приближение.

Скажу прямо, где я с ней расхожусь: 25 % — это очень щедро. На сервере со 128 ГБ вы отдаёте 32 ГБ под то, чего на типовом 1С-сервере просто нет: ни CLR, ни расширенных процедур, ни OLE Automation. Я закладываю 5–8 % и держу их как буфер, а не как гарантированный расход. Но там, где действительно есть линкованные серверы, SQLCLR или тяжёлый EDR — беру рекомендацию Microsoft почти буквально и оставляю 20 %. Универсального числа тут нет, и любой, кто называет одно значение на все случаи, просто не мерил.

Мой рабочий порядок расчёта на 128 ГБ и 32 логических ядрах: 128 ГБ физической − 6 ГБ на ОС и её кэши − 2 ГБ на стеки потоков (960 × 2048 КБ) − 8 ГБ на внешние аллокации и запас = 112 ГБ, округляю вниз до 108–110 ГБ. На 64 ГБ и 16 ядрах то же самое даёт: 64 − 4 (ОС) − 1,4 (704 потока × 2 МБ) − 4 = ~54 ГБ, ставлю 52 ГБ. На 32 ГБ: 32 − 4 − 1 − 2 = 25, ставлю 24 ГБ. И дальше неделю смотрю на Available MBytes под реальной нагрузкой — если он стабильно выше 10 % физической памяти, лимит можно осторожно поднять. Но это расчёт для выделенного сервера СУБД. Если на той же машине работает сервер 1С, из формулы обязательно вычитается ещё одна крупная статья — его процессы.

Для связки «SQL Server + сервер 1С на одном железе» я считаю так: max server memory = RAM − ОС (4 ГБ до 64 ГБ RAM) − стеки потоков SQL (расчётные max worker threads × 2 МБ) − пиковое потребление процессов 1С (сумма Private Bytes всех rphost, rmngr и ragent в самый загруженный час, а не в среднем) − запас на внешние аллокации внутри sqlservr.exe (2–3 ГБ без экзотики). Пик 1С снимаю счётчиками за неделю, а не беру «из головы»: на 20–30 пользователях он легко гуляет от 3 до 8 ГБ в зависимости от конфигураций и тяжёлых отчётов. Дополнительно в свойствах рабочего сервера 1С стоит задать ограничения памяти его процессов, чтобы разбухший rphost перезапускался кластером, а не выдавливал SQL Server в файл подкачки.

# суммарный Private Bytes процессов сервера 1С, ГБ
(Get-Process rphost, rmngr, ragent -ErrorAction SilentlyContinue |
  Measure-Object -Property PrivateMemorySize64 -Sum).Sum / 1GB

Применяется всё это без рестарта, что важно, когда в базе сидит смена:

EXECUTE sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
EXECUTE sp_configure 'max server memory', 32768;
GO
RECONFIGURE;
GO

SELECT [name], [value], [value_in_use]
FROM sys.configurations
WHERE [name] IN ('max server memory (MB)', 'min server memory (MB)');

Про min server memory отдельно. По умолчанию 0, и на физическом сервере с одним инстансом я его чаще всего таким и оставляю. Но если SQL живёт в виртуалке — ставлю осмысленное значение обязательно: это защита от того, что гипервизор под давлением начнёт отбирать память у гостя и раздевать buffer pool ниже приемлемого уровня. Одинаковые или почти одинаковые значения min и max Microsoft прямо не рекомендует, и я с этим согласен: вы просто лишаете движок возможности отдавать память в ответ на сигналы ОС.

Не ставьте max server memory равным min server memory. И не выставляйте значения около минимума 128 МБ — инстанс может вообще не подняться, придётся стартовать с ключом -f и откатывать настройку.
Порядок действий: Как я считаю max server memory руками — схема
Порядок действий: Как я считаю max server memory руками. Открыть схему в полном размере

Диагностика за пятнадцать минут: три запроса и один счётчик

Порядок действий у меня всегда один и тот же. Сначала — общая картина по процессу, чтобы понять, есть ли вообще дельта и какая она:

SELECT physical_memory_in_use_kb / 1024 AS process_physical_mb,
       locked_page_allocations_kb / 1024 AS locked_pages_mb,
       large_page_allocations_kb / 1024 AS large_pages_mb,
       virtual_address_space_committed_kb / 1024 AS vas_committed_mb,
       memory_utilization_percentage,
       process_physical_memory_low,
       process_virtual_memory_low
FROM sys.dm_os_process_memory;

SELECT sql_memory_model_desc,
       committed_kb / 1024 AS committed_mb,
       committed_target_kb / 1024 AS committed_target_mb
FROM sys.dm_os_sys_info;

Дальше — кто внутри движка занимает больше всех. Это отвечает на вопрос «а нормально ли распределена память под лимитом»:

SELECT TOP 15
       type,
       name,
       pages_kb / 1024 AS pages_mb,
       virtual_memory_committed_kb / 1024 AS vm_committed_mb,
       awe_allocated_kb / 1024 AS awe_mb
FROM sys.dm_os_memory_clerks
ORDER BY pages_kb DESC;

Здесь я смотрю на характерные перекосы: раздутый CACHESTORE_SQLCP — значит, летит вал непараметризованного ad hoc, лечится sp_executesql, процедурами или FORCED parameterization. Большой OBJECTSTORE_LOCK_MANAGER — кто-то берёт миллионы блокировок, ищем запрос и индекс. Заметный MEMORYCLERK_SQLQERESERVATIONS — тяжёлые memory grants, смотрим планы, лишние сортировки и подсказки MIN_GRANT_PERCENT/MAX_GRANT_PERCENT. Гигантский TokenAndPermUserStore — известная болячка, ограничивается трейс-флагом 4618.

И, наконец, ключевое сравнение для нашей темы: Process\Private Bytes против SQL Server:Memory Manager\Total Server Memory (KB). Если разница большая — она пришла снаружи движка: линкованный сервер, XP, SQLCLR, антивирусная библиотека. Microsoft в разделе про внутреннее давление от не-движковых модулей даёт ровно такой же рецепт и пример: Private Bytes 300 ГБ при Total Server Memory 250 ГБ означают примерно 50 ГБ вне движка. У именованного инстанса счётчик называется не SQLServer:Memory Manager, а MSSQL$ИМЯЭКЗЕМПЛЯРА:Memory Manager — на этом спотыкаются регулярно.

Отдельная ловушка — Lock Pages in Memory. Если привилегия выдана служебной учётке, память buffer pool выделяется через AWE-API и не попадает в Working Set. В диспетчере задач вы увидите у sqlservr.exe смешные 700 МБ и решите, что SQL вообще не работает. Проверяется одной строкой: SELECT sql_memory_model_desc FROM sys.dm_os_sys_info; — значение CONVENTIONAL означает, что LPIM не выдан, LOCK_PAGES означает, что выдан, LARGE_PAGES — что выдан вместе с трейс-флагом 834 (это уже экзотика, для большинства не нужна). Microsoft прямо пишет: при выданном LPIM типичные Private Bytes держатся в диапазоне 300 МБ — 1–2 ГБ, и если у вас там 4–5 ГБ, разницу опять же дала сторонняя DLL.

Проверяйте счётчики под нагрузкой, а не в обед и не сразу после рестарта службы. После старта инстанс проходит стадию ramp-up и заполняет buffer pool постепенно — снимок в этот момент покажет заниженные цифры и уведёт вас не туда.

Когда лимит действительно занижен, и почему это дороже «утечки»

Обратная крайность встречается у меня не реже. Админ увидел превышение, испугался, срезал max server memory вдвое — и получил вместо мнимой проблемы вполне реальную. Buffer pool сжался, страницы перестали держаться в памяти, выросли физические чтения, полезли ожидания PAGEIOLATCH, план-кэш начал вымываться и запросы стали чаще компилироваться заново. Пользователи это чувствуют как «1С стала тупить», а по железу вроде бы всё зелёное.

Ещё одна цена заниженного лимита — спилы memory grants в tempdb. При строчном режиме выполнения начальный грант превысить нельзя ни при каких условиях: если хэшу или сортировке не хватает памяти, операция уходит на диск. Хэш-спил живёт в workfile в tempdb, сортировочный — в worktable, и оба видны как Hash Warning и Sort Warnings. Итог — tempdb пухнет, диск греется, а вы искали проблему в оперативке.

Отдельно про панические ошибки, которые часто приписывают завышенному лимиту, хотя причина в другом. 701 — не хватило памяти на выполнение запроса, 8645 — не дождались гранта на сортировку/хэш, 802 — не удалось получить память под страницы buffer pool, 1204 — не хватило под блокировки. Практически всегда запрос, который упал, не является причиной: он просто оказался последним. Смотреть надо на клерков и на внешних потребителей, а не на текст упавшего запроса.

И про то, на что можно спокойно забить. Постоянный рост потребления SQL после старта — это не утечка, а штатное поведение динамического менеджера памяти, документация Microsoft говорит об этом прямым текстом. Разовое кратковременное превышение лимита во время перестроения columnstore-индекса или большого бэкапа — тоже норма, Resource Monitor уберёт его сам. Тревожиться стоит, когда дельта над лимитом устойчивая, измеряется гигабайтами и растёт день ото дня без возврата.

Экстренные DBCC FREEPROCCACHE, FREESYSTEMCACHE и FREESESSIONCACHE — это обезболивающее, а не лечение. На проде они сбрасывают кэши, которые придётся набирать заново, и первые минуты после них база работает заметно хуже.

Короткий чеклист: что делать по порядку

Если у вас прямо сейчас на руках сервер, где «SQL съел больше положенного», делайте по шагам и не перепрыгивайте. Первое — снимите Private Bytes процесса и Total Server Memory движка одновременно, а не по очереди. Второе — посчитайте дельту. До 1–2 ГБ на типовом сервере без экзотики это нормальный фон: стеки потоков плюс мелочь. Больше — идите смотреть sys.dm_os_loaded_modules и tasklist /M.

Третье — посмотрите на Memory\Available MBytes и на ошибку 17890 в логе SQL. Если доступной памяти в ОС меньше пары гигабайт или ошибка есть — проблема реальная и её надо решать сегодня. Если Available MBytes держится в комфортных пределах, а дельта стабильна — вы просто смотрели не на тот счётчик, и трогать ничего не нужно.

Четвёртое — сначала убираем потребителей снаружи движка: линкованные серверы переводим out of process снятием Allow inprocess (не все провайдеры это умеют, уточняйте у производителя), объекты OLE Automation при необходимости запускаем внешним процессом через контекст 4 в sp_OACreate, антивирусу и EDR прописываем исключения по каталогам данных и процессу. И только пятым шагом пересчитываем и правим сам лимит.

Что я в этой истории считаю приоритетом номер один и делаю у всех клиентов независимо от жалоб: явно выставленный max server memory вместо дефолтных двух миллиардов мегабайт и мониторинг Available MBytes с алертом. Всё остальное — уже точная настройка. А вот от привычки судить о здоровье SQL Server по диспетчеру задач лучше отучаться сразу: он показывает коммит процесса, в который входит всё, включая то, чем движок вообще не управляет.

Если сервер виртуальный — прежде чем считать что-либо, убедитесь, что хост не оверкоммитит память гостю. Пока ballooning отбирает у виртуалки RAM, любые расчёты лимита внутри гостя бессмысленны.
Порядок действий: Короткий чеклист: что делать по порядку — схема
Порядок действий: Короткий чеклист: что делать по порядку. Открыть схему в полном размере

Частые вопросы

sqlservr.exe в диспетчере задач больше max server memory на 3 ГБ. Это утечка?

Почти наверняка нет. Диспетчер задач показывает коммит всего процесса, а max server memory ограничивает только менеджер памяти движка. Снаружи лимита живут стеки рабочих потоков (2048 КБ на поток, при 32 логических CPU это около 1,9 ГБ), буферы бэкапа, DLL расширенных процедур, OLE DB провайдеры линкованных серверов, объекты sp_OA и инжектированные библиотеки антивирусов. Дельта в 1–3 ГБ на типовом сервере — фон. Тревожиться стоит, если дельта измеряется десятками гигабайт и растёт без отката.

Какое значение max server memory поставить на сервере со 128 ГБ RAM?

Мой рабочий расчёт: 128 ГБ минус 6 ГБ на ОС, минус память стеков потоков (расчётные max worker threads × 2 МБ, для 32 логических CPU это 960 × 2 МБ ≈ 1,9 ГБ), минус 5–8 % на внешние аллокации — получается около 108–110 ГБ. Microsoft советует вычитать 25 % на внешние аллокации, это осмысленно, если у вас есть линкованные серверы, SQLCLR или тяжёлый EDR, и избыточно на выделенном сервере СУБД под 1С. После настройки неделю наблюдайте за счётчиком Memory\Available MBytes под реальной нагрузкой.

SQL Server и сервер 1С на одной машине — как делить память?

Считайте лимит от остатка: RAM минус память ОС, минус стеки потоков SQL (расчётные max worker threads × 2 МБ), минус пиковое потребление процессов 1С (rphost, rmngr, ragent — снимайте счётчиком Private Bytes в самый загруженный час), минус 2–3 ГБ запаса на аллокации внутри sqlservr.exe вне лимита. Например, на 48 ГБ и 16 логических CPU при пике 1С в 7 ГБ выходит около 32 ГБ. После настройки неделю смотрите на Memory\Available MBytes: если он проседает ниже 1–2 ГБ, лимит завышен или 1С растёт сильнее, чем вы измерили.

Как понять, кто именно занял память сверх лимита?

Сравните счётчики Process(sqlservr)\Private Bytes и SQL Server:Memory Manager\Total Server Memory (KB). Разница — это то, что пришло не от движка. Дальше смотрите, какие модули загружены в процесс: `tasklist /M /FI "IMAGENAME eq sqlservr.exe"` и запрос к sys.dm_os_loaded_modules. Чаще всего находится OLE DB провайдер линкованного сервера в режиме Allow inprocess или библиотека антивируса/EDR. Часть провайдеров Microsoft отчитывается движку — их видно запросом к sys.dm_os_memory_clerks с type = 'MEMORYCLERK_HOST'.

Включена Lock Pages in Memory — почему в диспетчере задач у SQL всего 800 МБ?

Так и должно быть. При выданной привилегии Lock pages in memory память buffer pool выделяется через AWE-API и не попадает в Working Set процесса, поэтому диспетчер задач показывает обманчиво маленькую цифру. Проверить режим: `SELECT sql_memory_model_desc FROM sys.dm_os_sys_info;` — значение LOCK_PAGES означает, что LPIM активна. Смотрите реальное потребление через sys.dm_os_process_memory (столбцы physical_memory_in_use_kb и locked_page_allocations_kb) и счётчик Total Server Memory.

Что изменилось в управлении памятью в SQL Server 2025 по сравнению с 2022?

Архитектура памяти принципиально та же: единый «any size» page allocator, CLR внутри лимита, стеки потоков и прямые Windows-аллокации — снаружи. Главное практическое изменение — редакция Standard теперь поддерживает до 256 ГБ вместо прежних 128 ГБ в SQL Server 2022 и более ранних. Автоматическая уборка при over-commit (то, что раньше давал трейс-флаг 8121) включена по умолчанию ещё с SQL Server 2022 и продолжает работать так же.

Стоит ли выставлять min server memory равным max server memory?

Не стоит, Microsoft прямо не рекомендует ставить их равными или близкими. Так вы лишаете движок возможности отдавать память в ответ на сигналы ОС о нехватке. Разумное применение min server memory — виртуальные машины (защита от того, что гипервизор отберёт память у гостя) и хосты с несколькими инстансами, где нужно гарантировать каждому минимальный объём. На физическом сервере с одним инстансом дефолтный 0 обычно нормально работает.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 💬 MAX: +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи