Проблема при выделении памяти (С++/С)

 

101

аксакал

Есть процесс в операционной системе, который занимает 1,5 гигабайта.
Выдаем запрос на выделение 50 Мб адресного пространства с непрерывной адресацией, т.е. создаем масив (начало массива + длина).
Операционная система Windows выдает сообщение, что приложение потребовало слишком много памяти и будет закрыто. В итоге процесс падает. В системе установлено 2 гига оперативки, плюс ко всему прочему приложение откомпилировано с поддержкой ключа 3Gb, который также активирован и в операционной системе.
Начинаем разбираться.
Оказалось, что все приложения, которые загружены в память привязаны к конкретным ячейкам памяти, которые им занимаются и не освобождаются. В итоге может сложиться ситуация, когда разные приложения (в том числе системные) и, в том числе, наше, после работы с памятью (выделение/освобождение ячеек) сегментируют ее таким образом, что между ближайшими занятыми сегментами памяти размер не превышает некоего размера. И когда мы запрашиваем на выделение непрерывный участок памяти система выдает нам, что мол обломитесь ребятки - памяти нема.

Какой выход мы нашли: снизили размер запрашиваемого за раз сегмента памяти до 25 Мб. Это существенно повысило наши шансы на то, что мы сможем расположить массив в памяти, но как сами понимаете, это всего лишь повышает вероятность, а не является ответом на вопрос.
Ждем случая, когда у юзера софт опять упадет по причине этой причине с меньшим размером индексации, и будем еще больше мельчить размер запрашиваемого сегмента.

Вопрос в следующем:

1) Есть ли в Windows механизмы по оптимизации памяти, чтобы, например, время от времени при необходимости делать запрос на дефрагментацию памяти?

2) Есть ли в Windows механизмы по устанавливанию приоритетов для приложений при выделении памяти? Т.е. если мы делаем запрос на выделение памяти, а некое приложение лежит в памяти на нашем пути, то, если у нашего приложения приоритет выше, то система перенесет приложение с более низким приоритетом куда-нибудь.

Если будут ответы, то просьба подкрепить ответ ссылками (по возможности) или писать более развернуто.

Спасибо.
Если что непонятно написал, то готов переформулировать.
С уважением  
RU riven-mage #26.09.2006 20:06
+
-
edit
 

riven-mage

опытный

Что-то тут не то. Физическая память и виртуальная - вещи совершенно разные. Фрагментирована может быть только физическая память. Но процесс "не видит" физическую память, он видит только виртуальную - своё адресное пространство. В адресном пространстве процесса (строго говоря, задачи - в Windows задачей является нить - thread, process это группа нитей, разделяющих одно адресное пространство) не могут присутствовать другие процессы! Соответствие страниц физической и виртуальной памятей происходит ч/з таблицу дескрипторов задачи.

Если несколько процессов запросили много памяти, то АВТОМАТИЧЕСКИ происходит сброс страниц физической памяти на диск (в swap файл).

Т.е. скорее всего проблема в том, что система не смогла (не успела) сбросить достаточно памяти в файл подкачки.

Дефрагментации памяти нет и она не нужна. Массив фрагментирован в физической памяти, но в виртуальной он "виден" как непрерывный.

Все вышесказанное относится к архитектуре x86.

Какая архитектура ? Какая операционка конкретно ? Каким образом ты выделяешь память - через библиотечные функции или через Windows API (GlobalAlloc,VirtualAlloc) ?
What can change the nature of a man ?  
BG Реконструктор #27.09.2006 13:14
+
-
edit
 
riven-mage> Что-то тут не то. Физическая память и виртуальная - вещи совершенно разные. Фрагментирована может быть только физическая память. Но процесс "не видит" физическую память, он видит только виртуальную - своё адресное пространство.

Скорее всего, речь идет именно о фрагментации адресного пространства. Если работать блоками в 50 МБ, то пространство в 2 ГБ фрагментируется довольно быстро. Решение проблеммы, как мне кажется, только в написании собственного менажера памяти.
 

Sap

втянувшийся

Вы тут не учитываете следущий момент:
Общий размер памяти который NT может выделить одному процессу не может превышать 2 Гб. Еслиу вас процесс занимает 1.5ГБ, то за счёт системных объектов назначенных этому процессу (буфера в/в, стеки, таблицы вирт. памяти, запасы стека и кучи (guard pages) ), общий выделенный размер может быть равен 2Гб. Тогда при попытке выделить ещё немнго паямти получаем сообщение о недостатке памяти. В описаном случае скорее это и имеет место быть. Лечится применением функций WinAPi для работы с фирт памятью - там можно выделять большие области памяти, но доступ иметь через т.н. "окно". Копать WinAPI с MapUserPhysicalPages и VirtualAlloc.
 
Это сообщение редактировалось 27.09.2006 в 15:00

Sap

втянувшийся

Добавлю:
"Фрагментация" памяти - большей частью миф и соврменные WinXP/2k весьма успешно борятся с этим явлением. Поясняю - Фрагментация на уровне системы элементарно лечится страничным преобразованием и влияет лишь на время выделения больших объёмов памяти. Фрагментация в пределах процесса лечится прямыми руками программиста - в MSDN рекомендуется для часто выделемых/освобождаемых объектов выделять отдельную кучу - в этом случаем фрагментация перестаёт влиять на работу процесса. Даже в пределах одной кучи винда весьма эффективно борется с фргаментацией. Когда куча заканчиватся, то перед расширением кучи будет произведена принудительная дефрагментация. Более того желающие могут назначить для любой кучи (в т.ч для стандартной) свой собственный менеджер памяти (таких в инете много), но по разным причнимам сей путь кривой и бесперпективный.
Никаких приритетов при выделении памяти нет и быть не может. Каждый процесс обладает своим 2Гб адресным пространством в котором волен творить что захочет. При такой концепции приритеты просто бессмысленны - ведь адрессные пространтсва не пересекаются.

Ну и собственно мораль - если работаешь с объёмами памяти порядка гигабайта, то делать это надо ТОЛЬКО через функции работы с виртуальной памятью с доступом через окно. Иначе будт глюки вида "тут работает, а там не работает".
 

Sap

втянувшийся

riven-mage>> Что-то тут не то. Физическая память и виртуальная - вещи совершенно разные. Фрагментирована может быть только физическая память. Но процесс "не видит" физическую память, он видит только виртуальную - своё адресное пространство.
Реконструктор> Скорее всего, речь идет именно о фрагментации адресного пространства. Если работать блоками в 50 МБ, то пространство в 2 ГБ фрагментируется довольно быстро. Решение проблеммы, как мне кажется, только в написании собственного менажера памяти.
Если работаешь с блоками по 50Мб, то пространство не фрагментируется вообще (если конечно не в стеке выделять и не через malloc), ибо размер выделяемой области намного больше размера страницы памяти. И вся фрагментация решается страничным преобразованием "на лету".
 

Sap

втянувшийся

Что за дурацкий кот у меня в аватаре (был) ?!
 
Это сообщение редактировалось 27.09.2006 в 17:26

Tais

администратор

Sap> Что за дурацкий кот у меня в аватаре ?!

Наоборот, такой классный котик %)))
 
+
-
edit
 

Balancer

администратор
★★★★★
Sap> Что за дурацкий кот у меня в аватаре ?!

Сверху страницы "Объявления" для кого делаются? Первая же строчка.
 
BG Реконструктор #27.09.2006 16:58
+
-
edit
 
Sap> Если работаешь с блоками по 50Мб, то пространство не фрагментируется вообще (если конечно не в стеке выделять и не через malloc), ибо размер выделяемой области намного больше размера страницы памяти. И вся фрагментация решается страничным преобразованием "на лету".

Подумай глубже. У человека система выдает ошибку о нехватке памяти. С чего бы это?
 

Sap

втянувшийся

А человеку было предупреждение о нехватке файла подкачки? :) Или при нехватке памяти винда снимает процессы? :) Если бы была нехватка памяти, то функция выделения памяти вернула бы или исключение или указатель на ноль, но уж никак не снимала бы задачу.
У человека кончилось адресное пространство процесса.
 

Sap

втянувшийся

Кстати проверяется элементарно. Зацикливаем задачу перед выделением последних 50 Мб, а потом какой-нибдь утилитой смотрим значение total pages allocated для данного процесса. Множим на размер страницы. Если получается 2Гб, то усё - финита ля комедия.
 
BG Реконструктор #27.09.2006 17:39
+
-
edit
 
Sap> У человека кончилось адресное пространство процесса.

Ну, приплыли. О чем я говорил выше?
 

Sap

втянувшийся

Sap>> У человека кончилось адресное пространство процесса.
Реконструктор> Ну, приплыли. О чем я говорил выше?
адрессное пространство и объём памяти это разные вещи. Памяти может быть ещё хоть сто оргомных гигабайт, но вделить их этот процесс не сможет. А другой сможет. Опять же в адресное пространство процесса входят кэши, стек, буфера обмена с диском и другими процессами, системные таблицы и ещё чёрте что. И главное - туда же входят образа загруженных DLL в т.ч. некоторых системных, что сразу может уменьшить доступный объём на сотню-другую метров.
Если бы автор темы работал с памятью при помощи функций MapUserPhysicalPages и VirtualAlloc, то смог бы выделить ещё очень и очень много памяти.
 
RU riven-mage #28.09.2006 11:41
+
-
edit
 

riven-mage

опытный

Итого:

Если выделяешь большие объемы памяти - работай ч/з VirtualAlloc.

Если маленькие, то либо используй сборщик мусора, например этот: A garbage collector for C and C++ , либо напиши свой простенький менеджер памяти.
What can change the nature of a man ?  

в начало страницы | новое
 
Поиск
Поддержка
Поддержи форум!
ЯндексЯндекс. ДеньгиХочу такую же кнопку
Настройки
Твиттер сайта
Статистика
Рейтинг@Mail.ru