Краткий ответ
Всплывающее окно «Недостаточно памяти» говорит о том, что у вас исчерпано ограничение на частную выделенную память - тип виртуальной памяти. Не то, что у вас заканчивается ОЗУ (физическая память). Неважно, сколько у вас доступно оперативной памяти. Наличие большого количества доступной оперативной памяти не позволяет вам превысить предел фиксации. Лимит фиксации - это сумма вашего общего объема ОЗУ (используется или нет!) Плюс ваш текущий размер файла подкачки.
И наоборот, то, что «использует» лимит фиксации (которое главным образом является созданием частного виртуального адресного пространства процесса), не обязательно использует какую-либо оперативную память! Но ОС не допустит ее создания, если не знает, что есть место для ее хранения, если это когда-либо понадобится. Таким образом, вы можете столкнуться с лимитом коммитов без использования всей вашей оперативной памяти или даже большей части вашей оперативной памяти.
Вот почему вы не должны работать без файла подкачки. Обратите внимание, что файл подкачки может вообще не записываться! Но это все же позволит вам избежать ошибок «недостаточно памяти» и «недостаточно памяти».
Промежуточный ответ
На самом деле в Windows нет сообщения об ошибке нехватки оперативной памяти. То, что у вас заканчивается, это «предел коммитов».
График «Система» в этой версии Process Explorer имеет плохое имя. Он должен быть помечен как «совершить заряд». (В версии, которая у меня есть, она называется «Системная фиксация». Лучше, но все же не полностью согласованной.) В любом случае «текущая» высота графика показывает то, что ниже в текстовом разделе отображается как «Фиксация» - « Current », а максимальная высота графика представляет« Commit Charge »-« Limit ».
«Зафиксировать плату» относится к виртуальному адресному пространству, которое поддерживается файлом подкачки (если он у вас есть) - другими словами, если он не может уместиться в ОЗУ, остальная часть помещается в файл подкачки. (Существуют другие типы vas, которые либо поддерживаются другими файлами - они называются «mapped» vas - или которые должны постоянно находиться в оперативной памяти; последний называется «nonpageable».) «Предел фиксации» - это максимум, который «поручить» может быть. Он равен размеру вашей оперативной памяти плюс размер файла подкачки.
У вас, очевидно, нет файла подкачки (я могу сказать, потому что ваш предел фиксации равен размеру ОЗУ), поэтому предел фиксации - это просто размер ОЗУ.
Видимо различные программы + ОС использовали почти все максимально возможное коммит.
Это не имеет прямого отношения к тому, сколько оперативной памяти свободно или доступно. Да, у вас есть около 4,5 ГБ оперативной памяти. Это не значит, что вы можете превысить лимит коммитов. Выделенная память не обязательно использует ОЗУ и не ограничена объемом доступной ОЗУ.
Вам нужно либо снова включить файл подкачки - используя этот многообещающий файл, я бы предложил файл подкачки размером 16 ГБ, потому что вы не хотите заставлять ОС хранить в ОЗУ столько всего этого, а файл подкачки работает лучше всего, если он имеет много свободного места - или добавить больше оперативной памяти. Гораздо больше. Для хорошей производительности у вас должно быть достаточно места в оперативной памяти для кода и других вещей, которые не поддерживаются файлом подкачки (но могут быть перенесены в другие файлы).
Очень длинный ответ
(но все же намного короче, чем глава по управлению памятью Windows Internals ...)
Предположим, что программа выделяет 100 МБ приватной виртуальной памяти процесса. Это делается с помощью вызова VirtualAlloc с параметром commit. Это приведет к увеличению «фиксированного сбора» на 100 МБ. Но это «распределение» фактически не использует ОЗУ! ОЗУ используется только при первом обращении к некоторой части вновь созданного виртуального адресного пространства .
Как ОЗУ в конечном итоге используется
(если это когда-либо делает)
Первоначальный доступ к вновь зафиксированному пространству почти всегда был бы записью в память (чтение вновь выделенных частных файлов перед записью почти всегда является ошибкой программирования, поскольку его начальное содержимое, строго говоря, не определено). Но читайте или пишите, результат, когда вы в первый раз касаетесь страницы недавно выделенной области, является ошибкой страницы . Хотя слово «ошибка» звучит плохо, ошибки страницы являются полностью ожидаемым и даже обязательным событием в ОС виртуальной памяти.
В ответ на этот конкретный тип ошибки страницы пейджер (часть диспетчера памяти операционной системы, которую я иногда сокращенно обозначаю как «Mm») будет:
- выделять физическую страницу ОЗУ (в идеале из списка нулевых страниц, но в любом случае это происходит из того, что Windows называет «доступным»: список нулевых, свободных или резервных страниц в том порядке предпочтений);
- заполните запись таблицы страниц, чтобы связать физическую страницу с виртуальной страницей; и наконец
- отклонить исключение ошибки страницы.
После чего код, который сделал ссылку на память, повторно выполнит инструкцию, которая вызвала ошибку страницы, и на этот раз ссылка будет успешной.
Мы говорим, что страница «вломана» в рабочий набор процесса и в оперативную память. В диспетчере задач это будет выглядеть как увеличение «частного рабочего набора» процесса на одну страницу (4 КБ). И сокращение доступной физической памяти на одну страницу. (Последнее может быть трудно заметить на занятой машине.)
Примечание 1: эта ошибка страницы не связана с чтением с диска. Никогда ранее недоступная страница выделенной виртуальной памяти не начинает жизнь на диске; он не имеет места на диске , чтобы прочитать его из . Он просто «материализуется» на ранее доступной странице оперативной памяти. Статистически, на самом деле, большинство сбоев страниц разрешается в ОЗУ либо на общие страницы, которые уже находятся в ОЗУ для других процессов, либо в кэшах страниц - в резервных или измененных списках, либо в виде страниц с нулевым требованием, подобных этой.
Примечание 2: требуется только одна страница, 4096 байт, из «Доступно». Зафиксированное никогда не затрагиваемое адресное пространство обычно реализуется - с ошибками - только по одной странице за раз, поскольку каждая страница «касается» впервые. Не было бы никакого улучшения, никакого преимущества, делая больше одновременно; это займет всего n раз больше времени. Напротив, когда страницы должны быть прочитаны с диска, предпринимается попытка «чтения», поскольку подавляющее большинство времени при чтении с диска приходится на каждую операцию, а не на фактическую передачу данных. Сумма "совершено" остается на уровне 100 МБ; тот факт, что одна или несколько страниц были повреждены, не уменьшает плату за фиксацию.
Заметка 3:Предположим, у нас есть 4 ГБ «доступной» оперативной памяти. Это означает, что мы можем ссылаться на уже выделенную, но никогда ранее не указанную выделенную память еще миллион раз (4 ГБ / 4096), прежде чем у нас не будет ОЗУ. В этот момент, если у нас есть файл подкачки, как предполагали Дэвид Катлер и Лу Пераццоли, некоторые из страниц с самой давней давностью в ОЗУ будут сохранены на диске и затем предоставлены для использования при устранении этих более недавних ошибок страниц. (На самом деле ОС будет инициировать методы восстановления ОЗУ, такие как «обрезка рабочего набора», а до этого и фактические записи в файл подкачки кэшируются и группируются в измененном списке страниц для эффективности, и и ...) Ничто из этого не повлияет на "совершенный" счет. Это относится, однако, к «пределу коммитов». Если нет места для всех
И это продолжает происходить ...
Но давайте предположим, что мы еще не сделали эти миллионы ссылок, и по-прежнему доступно около 4 ГБ страниц. Теперь давайте предположим, что тот же процесс - или другой, не имеет значения - выполняет другой VirtualAlloc, на этот раз, скажем, выделено 200 МБ. Опять же, эти 200 МБ добавляются к плате за фиксацию и не удаляют ОЗУ из доступного. Простое адресное пространство VirtualAlloc не использует соответствующий объем ОЗУ, а наличие низкого «доступного» ОЗУ не ограничивает объем адресного пространства, которое вы можете использовать в VirtualAlloc (равно как и наличие большого объема ОЗУ не увеличивает его).
(Ну, ладно ... есть небольшая часть издержек, составляющая одну (страничную!) Страницу, которая используется для таблицы страниц на каждые 2 МБ (4 МБ, если вы используете систему x86, не-PAE) из выделено виртуальное адресное пространство, и существует «дескриптор виртуального адреса» в несколько десятков байтов для каждого виртуально непрерывного выделенного диапазона.)
Таким образом, это возможно - и часто! - использовать много «фиксации заряда» при использовании только небольшого количества оперативной памяти.
Итак, если «фиксация» виртуального адресного пространства не использует ОЗУ, почему должен быть предел?
Потому что «плата за фиксацию» действительно представляет потенциальное будущее использование места для хранения. «Ограничение фиксации» представляет собой общий объем памяти (ОЗУ + пространство файла подкачки), доступный для хранения таких выделений, если на них когда-либо действительно будут ссылаться, и, следовательно, их необходимо хранить где-то.
Когда Mm утверждает запрос VirtualAlloc, он обещает - «принятие обязательства» - что все последующие обращения к памяти в выделенной области будут успешными; они могут привести к сбоям страниц, но все эти ошибки можно будет устранить, поскольку в нем достаточно места для хранения содержимого всех этих страниц, будь то в ОЗУ или в файле подкачки. Mm знает об этом, потому что знает, сколько там места для хранения (лимит фиксации) и сколько уже было «зафиксировано» (текущий заряд фиксации).
(Но все эти страницы еще не обязательно были доступны, поэтому не обязательно иметь фактический объем памяти, который можно было бы согласовать с выделенной суммой в любой момент времени.)
Итак ... Как насчет "системы не хватает памяти"?
Если вы попытаетесь использовать VirtualAlloc, и текущая плата за фиксацию плюс запрошенный размер выделения приведет к превышению лимита фиксации, а ОС не сможет развернуть файл подкачки, чтобы увеличить предел фиксации ... вы получите всплывающее окно «недостаточно памяти». вверх, и процесс видит вызов VirtualAlloc FAIL. Большинство программ просто опустят руки и умрут в этот момент. Некоторые будут слепо нажимать, предполагая, что вызов выполнен успешно, и потерпят неудачу позже, когда они попытаются сослаться на регион, который, по их мнению, они выделили.
Еще раз (извините за повторение): не имеет значения, сколько у вас доступно ОЗУ. ОС обещала, что ОЗУ или пространство подкачки будут доступны, когда это необходимо, но это обещание не вычитает из «Доступно». Доступная оперативная память используется коммитом vm только при первом обращении к нему, что и является причиной его сбоя ... т.е. реализуется в физической памяти. И просто выделение (= выделение) виртуальной памяти не делает этого. Он занимает только свободное виртуальное адресное пространство и выделяет из него полезное виртуальное адресное пространство.
Но в «из памяти» случае был запрос выделения для выделенной памяти, и ОС добавил ток фиксацию заряда до размера этого neew запроса ... и обнаружил , что общая сумма составляет более чем совершить предел. Поэтому, если ОС утвердит этот новый, и после этого на все это пространство будет ссылаться, то не будет никаких реальных мест (RAM + pagefile) для хранения всего этого.
ОС не позволит этого. Это не позволит выделить больше сосудов, чем у него есть место, чтобы сохранить его в худшем случае - даже если все это «сломано». Это цель «предела коммитов».
Я говорю вам три раза, я говорю вам три раза, я говорю вам три раза: объем доступной оперативной памяти не имеет значения. То, что выделенное виртуальное пространство еще не использует все это пространство хранения, не имеет значения. Windows не может «зафиксировать» виртуальное выделение, если она «не сможет» в будущем ошибаться.
Обратите внимание, что существует другой тип vas, называемый «mapped», который в основном используется для кода и для доступа к большим файлам данных, но он не взимается с «commit commit» и не ограничен «limit commit». Это связано с тем, что он имеет свою собственную область хранения, файлы, которые «сопоставлены» с ней. Единственным ограничением для «сопоставленных» vas является количество дискового пространства, которое у вас есть для сопоставленных файлов, и количество свободных vas в вашем процессе для их сопоставления.
Но когда я смотрю на систему, я еще не совсем на пределе коммитов?
Это в основном проблема измерения и учета. Вы просматриваете систему после того, как вызов VirtualAlloc уже был опробован и не выполнен.
Предположим, у вас осталось всего 500 МБ, а какая-то программа пыталась использовать VirtualAlloc 600 МБ. Попытка не удалась. Затем вы смотрите на систему и говорите: «Что? Осталось еще 500 МБ!» Фактически, к тому времени может быть еще больше, потому что к этому моменту рассматриваемый процесс, вероятно, полностью исчезнет, поэтому ВСЕ его ранее выделенная выделенная память была освобождена.
Беда в том , что вы не можете вернуться в прошлое и посмотреть , что совершить заряд был в тот момент , была сделана попытка Alloc. И вы также не знаете, сколько места было для этой попытки. Таким образом, вы не можете окончательно понять, почему попытка не удалась, или сколько еще "предела коммитов" понадобилось бы, чтобы это сработало.
Я видел "системе не хватает памяти". Что это такое?
Если в приведенном выше случае ОС МОЖЕТ развернуть файл подкачки (то есть вы оставите для него значение по умолчанию «управляемая системой», или вы управляете им, но вы установили максимум больше исходного, И достаточно свободного места на диске), и такое расширение увеличивает предел фиксации в достаточной степени, чтобы позволить вызову VirtualAlloc успешным образом, затем ... Mm расширяет файл подкачки, и вызов VirtualAlloc выполняется успешно.
И вот, когда вы видите, «система работает низко на памяти». Это раннее предупреждение о том, что если все будет продолжаться без смягчения, вы, скорее всего, скоро увидите предупреждение «недостаточно памяти». Время закрыть некоторые приложения. Я бы начал с окон вашего браузера.
И ты думаешь, это хорошо? Расширение файла подкачки - зло !!!
Нет, это не так. Видите, ОС на самом деле не "расширяет" существующий файл. Это просто выделяет новую степень. Эффект очень похож на любой другой несмежный файл. Содержимое старого файла подкачки остается там, где оно есть; их не нужно копировать в новое место или что-то в этом роде. Поскольку большинство операций ввода-вывода файла подкачки происходит относительно небольшими порциями по сравнению с размером файла подкачки, шансы того, что любая передача будет пересекать границу экстента, действительно довольно редки, поэтому фрагментация не повредит, если не будет чрезмерной.
Наконец, как только все процессы, которые «зафиксировали» пространство в расширении, завершили работу (при выключении ОС, если не раньше), экстенты будут автоматически освобождены, и файл подкачки вернется к своему предыдущему размеру и распределению - если он был смежным до этого, он это снова.
Поэтому разрешение расширения файла подкачки действует как полностью бесплатная сеть безопасности: если вы разрешаете это, но система никогда не нуждается в этом, система не будет «постоянно расширять и сжимать файл подкачки», как это часто требуется, поэтому ничего не будет стоить . И если вам это когда-нибудь понадобится, это избавит вас от сбоев приложений с ошибками «нехватки виртуальной памяти».
Но но НО...
Я читал на десятках веб-сайтов, что если вы разрешите расширение файла подкачки, Windows будет постоянно расширять и сжимать файл подкачки, и это приведет к фрагментации файла подкачки, пока вы не выполните его дефрагментацию.
Они просто не правы.
Если вы никогда не видели всплывающее окно «Недостаточно памяти» (или, в более старых версиях, «Недостаточно памяти»), ОС никогда не расширяла ваш файл подкачки.
Если вы видите это всплывающее окно, то это говорит о том, что ваш начальный размер файла подкачки слишком мал. (Я хотел бы установить его примерно в 4 раза выше максимального наблюдаемого использования; т. Е. Счетчик perfmon "% pagefile Использование пика" должен быть меньше 25%. Причина: пространство Pagefile управляется как любая другая куча, и он лучше всего работает с большим количеством свободного пространства играть в.)
Но почему они просто ...
Кто-то может возразить, что ОС должна просто разрешить выделение, а затем дать сбоям ссылки, если не доступно ОЗУ для устранения ошибок страницы. Другими словами, выше, где мы описали, как работает ошибка начальной страницы, что, если «выделить выделенную физическую страницу ОЗУ» (шаг 1) невозможно, потому что не было ни одной доступной, и не было места осталось на странице что-нибудь сделать доступным?
Тогда пейджер не сможет устранить ошибку страницы. Это должно было бы позволить отчету об исключении (сбое страницы) возвращать отказавший поток, вероятно, измененный на другой код исключения.
Философия проектирования заключается в том, что VirtualAlloc будет возвращать ноль (технически NULL-указатель) вместо адреса, если вы исчерпали предел фиксации, и вполне разумно ожидать, что программист узнает, что вызов VirtualAlloc может завершиться неудачно. Поэтому программисты должны проверить этот случай и сделать что-то разумное в ответ (например, дать вам возможность сохранить свою работу до этого момента, а затем завершить программу «изящно»). (Программисты: вы проверяете возвращение NULL-указателя из malloc, new и т. Д., Да? Тогда почему бы вам не сделать этого?)
Но программисты не должны ожидать, что простая ссылка на память, как
i = 0; // initialize loop counter
может произойти сбой - нет, если он находится в области успешно зафиксированного адресного пространства. (Или сопоставленное адресное пространство, если на то пошло.) Но это то, что могло бы произойти, если бы придерживалась философии «разрешить чрезмерное выделение памяти, позволить ссылке на память потерпеть неудачу».
К сожалению, ссылка на память, подобная приведенной в строке кода, просто не имеет удобного способа вернуть плохой статус! Они просто должны работать , как сложение и вычитание. Единственный способ сообщить о таких сбоях - это сделать исключения. Таким образом, чтобы обработать их, программист должен был бы обернуть всю программу в обработчик исключений. (попробуй ... поймай и все такое.)
Это может быть сделано ... Но обработчику было бы трудно знать, как "делать правильные вещи" в ответ на эти исключения, поскольку в коде было бы очень много точек, где они могут возникнуть. (В частности, они могут возникать при каждой ссылке на память на память VirtualAlloc, на память, выделенную с помощью malloc или new ... и на все локальные переменные, а также на стек, так как стек тоже VirtualAlloc.)
Короче говоря, заставить программу изящно провалиться в этих случаях было бы очень сложно.
С другой стороны, довольно легко проверить, возвращает ли NULL-указатель возвращенный из VirtualAlloc (или malloc или new, если на то пошло, хотя они не совсем одно и то же), а затем сделать что-то разумное ... например, не пытаться идти и делать то, что было программой, для которой требуется это виртуальное пространство. И, возможно, спросите пользователя, хотят ли они сохранить свою работу до сих пор, если таковые имеются. (Конечно, слишком много приложений не удосуживаются сделать даже так много.)
Другие пользователи commit
Между прочим, «предел фиксации» не уменьшается благодаря различным выделениям ОС, таким как пейджинговый и невыгружаемый пул, список PFN и т. Д .; они просто заряжены, чтобы совершить обвинение, как они происходят. Кроме того, ни на коммит-заряд, ни на предел коммитов не влияет размер видеопамяти или даже «окна» видеопамяти.
Проверь это сам
Вы можете продемонстрировать все это с помощью инструмента testlimit с сайта SysInternals. Опция -m выделит выделенное адресное пространство, но не "коснется" его, поэтому не вызовет выделение ОЗУ. Принимая во внимание, что опция -d будет выделять и также ссылаться на страницы, вызывая как увеличение комиссии за коммит, так и уменьшение доступной оперативной памяти.
Ссылки
Windows Internals от Руссиновича, Соломона и Ионеску. Есть даже демонстрации, позволяющие вам доказать все эти моменты с помощью инструмента testlimit. Тем не менее, я должен предупредить вас, что, если вы думаете, что это было долго, предупреждаем: одна только глава Mm - это 200 страниц; Выше очень упрощенная версия. (Пожалуйста, взгляните также на раздел «Благодарности» во Введении.)
Смотрите также документацию MSDN VirtualAlloc