Итак, у меня есть нативное приложение C ++, и оно должно отслеживать множество вещей в течение длительных периодов времени. Недостаточно памяти, когда диспетчер задач говорит, что процесс достигает где-то между 800 и 1200 МБ памяти, когда предел должен быть около 2 ГБ.
Я наконец понял, что происходит, когда я запустил VMMap против моего процесса, но это только дало мне больше вопросов. Что я обнаружил:
Пример этих пар субблоков: (не мое приложение, но идея та же)
http://www.flickr.com/photos/95123032@N00/5280550393
Кажется, что, когда один блок приватных данных полностью фиксируется, выделяется новый блок (обычно такой же или в два раза больше предыдущего). Звучит справедливо. Тем не менее, я видел 3 блока, каждый размером более 100 МБ и менее 30 МБ. Мое приложение не должно вести себя так (т. Е. Использовать 400 МБ, а затем уменьшить на 300 МБ в течение нескольких часов), что это было бы возможно.
Насколько я могу судить, «Размер» — это фактический объем адресного пространства виртуальной памяти, который был выделен. «Committed» — это количество «Size», которое фактически используется (то есть через вызовы new / malloc). Если это действительно так, то почему существует такая огромная несоответствие между Size и Commited? И почему он выделяет блоки размером несколько сотен мегабайт?
Несколько странно то, что при работе в Windows 7 поведение совершенно иное. В то время как на 2003 Server приложение использует личные данные, в Windows 7 — Heap. Так … почему? Почему VMMap показывает в основном использование личных данных в 2003 году, но в основном использование кучи в 7? Какая разница? Ну, одно отличие состоит в том, что я не могу использовать кнопку «Распределение кучи …» в VMMap, чтобы увидеть, где размещаются все эти частные данные.
Я начинал задаваться вопросом, не вызывало ли это чрезмерное использование std :: string, так как строки, которые я распознал в парах (упомянутых выше), в основном состояли из строк, хранящихся в std :: string, которые часто создавались и уничтожались (подразумевая много распределения / освобождения памяти). Я преобразовал все, что мог, чтобы использовать массивы символов или память из пула памяти, но это, похоже, не дало результата. Все другие мои новые / часто удаляемые объекты уже имеют свои собственные пулы памяти.
Я также узнал о низкой куче фрагментации, поэтому я попытался включить это, но это также не имело значения. Я думаю, это потому, что Windows 2003 на самом деле не использует кучу. VMMap показывает, что куча с низкой фрагментацией включена, но поскольку она на самом деле не используется (то есть вместо этого она использует личные данные), на самом деле это не имеет значения.
На самом деле кажется, что эти пары субблоков фрагментируют большие блоки Private Data, что заставляет ОС выделять новые блоки. В конце концов, фрагментация становится настолько плохой, что, несмотря на то, что есть много свободного места, ни один из них, кажется, не может быть использован, и процессу не хватает памяти.
Итак, мои вопросы:
Частные данные — это всего лишь классификация всей памяти, которая не распределяется между двумя или более процессами. Куча, перемещенные dll-страницы, стеки всех потоков в процессе, файлы с общей памятью и т. Д. Попадают в категорию личных данных.
ОС не сможет выполнить запрос памяти у процесса (через VirtualAlloc), если выполняется одно из условий,
Помимо этого выделение кучи может произойти сбой по своим собственным причинам, например, во время расширения они будут фактически пытаться получить больше памяти, чем размер запроса на выделение, который вызвал расширение — и если это не удается, они могут просто потерпеть неудачу — хотя фактический запрошенный размер может быть доступным через VirtualAlloc.
Мало что может накопить память,
когда диспетчер задач говорит, что процесс достигает где-то между 800 и 1200 МБ памяти, когда ограничение должно быть около 2 ГБ
Вероятно, вы смотрите на «Рабочий набор» в диспетчере задач, в то время как ограничение 2 ГБ для виртуальной памяти. Диспетчер задач не показывает количество зарезервированных виртуальных машин; он покажет совершенную сумму.
«Committed» — это количество «Size», которое фактически используется (то есть через вызовы new / malloc).
Нет, «Принятый» означает, что вы действительно коснулись страницы (то есть пошли по адресу и выполнили операцию загрузки или сохранения).
1. Почему Windows Server 2003 использует личные данные вместо кучи?
Согласно «Справочнику администратора Windows Sysinternals» Марка Руссиновича и Аарона Маргосиса:
Память личных данных — это память, выделенная VirtualAlloc и
это больше не обрабатывается диспетчером кучи или средой выполнения .Net
Таким образом, либо ваша программа по-разному управляет своей памятью в двух ОС, либо VMmap не может определить способ управления этой памятью как кучу в Windows Server 2003.
4. Есть ли что-то, что я пропускаю или стоило бы попробовать?
Вы можете работать с ограничением 3 ГБ в 32-разрядной ОС и 4 ГБ для 32-разрядных процессов в 64-разрядной ОС. Google для «/ 3G» и «/ 4G».
Отличным источником информации о подобных вещах является книга Марка Руссиновича, Дэвида Соломона и Алекса Ионеску «Windows Internals 6th Edition».
Я сталкиваюсь с той же проблемой.
В Windows 2003 мое приложение вызывает исключение нехватки памяти в модуле C ++ / CLI при попытке выделить массив размером 22 МБ с помощью gcnew. Тот же процесс отлично работает в Windows 7.
VMMap показывает, что запись «личных данных» в win2003 составляет почти 2 ГБ. После того, как я включил / 3GB флаг, эта запись также увеличилась почти до 3GB. Запись «куча» составляет около 14 МБ, а «управляемая куча» — ничто!
В windows 7 «личные данные» составляют всего 62 МБ, «куча» — 316 МБ, а «управляемая куча» — 397 МБ. Полное использование памяти намного меньше чем win2003.