2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 проблемы с выделением памяти
Сообщение05.09.2024, 16:30 
При попытке выделить большой кусок памяти, функции malloc() и realloc() возвращают ненулевой указатель,
но при записи в выделенную область данных, в какой то момент возникает ошибка сегментации. Подмечено,
что ошибки возникают при достижении объёма памяти 32 Гб, хотя доступно 64 Гб. Т.е. если выделяется менее 32 Гб,
то программа отрабатывает нормально. Но если требуется выделить больше, например 45 Гб, то возникают вышеописанные ошибки сегментации. Функция info.freeram прямо перед началом выделения памяти, показывает, что доступной памяти достаточно.
В чём может быть проблема?

 
 
 
 Re: проблемы с выделением памяти
Сообщение05.09.2024, 21:07 
Проверьте, нет ли где непреднамеренных преобразований типов целого или указателя для самого размера и для полученного указателя.
(Вообще, хорошо бы в теме указать, что за платформа используется и компилятор.)

 
 
 
 Re: проблемы с выделением памяти
Сообщение05.09.2024, 22:30 
gcc под linux
проверял, думал uint8_t занимает 2 байта, но sizeof(uint8_t) выдаёт 1.
В диспетчере задач тоже видно, что сбой происходит при увеличении объёма занятой памяти до 32 Гб, странное какое то совпадение.
В самой системе $ free выдаёт total, free, available примерно 64 Гб, ну и прямо перед выделением памяти через info.freeram определяется примерно 64 Гб, никаких выделений после этого не делается, только копирование, сначала даже всё работает, но как доходит до 32Гб, вылетает ошибка сегментирования

 
 
 
 Re: проблемы с выделением памяти
Сообщение05.09.2024, 22:45 
А sizeof(char*) точно равен 8?

 
 
 
 Re: проблемы с выделением памяти
Сообщение05.09.2024, 23:08 
Напишите простой тест, возможно, локализующий вашу проблему. Выделите массив uint8_t заданного константой размера, и заполните его последовательно в цикле хоть нулями. Больше эта программа не должна делать ничего.

 
 
 
 Re: проблемы с выделением памяти
Сообщение05.09.2024, 23:33 
realeugene в сообщении #1653421 писал(а):
А sizeof(char*) точно равен 8?

именно так

realeugene в сообщении #1653421 писал(а):
Напишите простой тест, возможно, локализующий вашу проблему

этот тест работает отлично, заполняются все 64 Гб

 
 
 
 Re: проблемы с выделением памяти
Сообщение05.09.2024, 23:50 
Аватара пользователя
Missir в сообщении #1653422 писал(а):
этот тест работает отлично, заполняются все 64 Гб

а считываются ли? вместо нулей заполнить 1.0f, в отдельном цикле считать и вывести сумму.

 
 
 
 Re: проблемы с выделением памяти
Сообщение06.09.2024, 00:27 
Legioner93 в сообщении #1653424 писал(а):
а считываются ли?

я писал не нули, а i/1000000000 (чтобы помещалось в uint8) последний байт считался нормально

 
 
 
 Re: проблемы с выделением памяти
Сообщение06.09.2024, 01:22 
Missir в сообщении #1653422 писал(а):
этот тест работает отлично, заполняются все 64 Гб
Скорее всего, у вас на самом деле из-за ошибки в вашем коде происходит обращение по неправильному адресу. Например, вы индексируете 32-битным целым массив двойных плавающих чисел. Или массив указателей.

 
 
 
 Re: проблемы с выделением памяти
Сообщение06.09.2024, 02:34 
realeugene в сообщении #1653428 писал(а):
Скорее всего, у вас на самом деле из-за ошибки в вашем коде происходит обращение по неправильному адресу

действительно, была ошибка, при определённых условиях он зацикливался, и писал до бесконечности, то что 32 Гб, это случайное совпадение. Исправил, сейчас обрабатывает эти данные без ошибок. Память используется вся. Всем большое спасибо

 
 
 
 Re: проблемы с выделением памяти
Сообщение07.09.2024, 23:33 
Аватара пользователя
Missir в сообщении #1653363 писал(а):
При попытке выделить большой кусок памяти, функции malloc() и realloc() возвращают ненулевой указатель,
но при записи в выделенную область данных, в какой то момент возникает ошибка сегментации.


Ну вообще-то вы описываете классические симптомы поведения виртуальной памяти в системе с разрешенным overcommit.

То есть при выделении памяти никакого физического выделения не происходит, а происходит лишь резервирование соответствующего диапазона адресов в адресном пространстве процесса. Никаких физических ресурсов за этими адресами изначально не стоит. То есть вам изначально выделяют "воображаемую" память. Вы получаете не память, а лишь диапазон адресов.

Выделение физических ресурсов, т.е. сопоставление вашему диапазону адресов настоящих физических страниц в ОЗУ и/или в своп-файле, начнется только тогда, когда вы начнете физически записывать в эту память данные. Оно будет делаться постранично (по 4 кб) по мере необходимости. И если в какой-то момент окажется, что физических ресурсов недостаточно, вы получите ошибку при записи в как будто уже выделенную "вашу" память.

То есть выделение памяти в такой системе - это не более чем вялое обещание, что память "может быть найдется", когда вы действительно начнете с ней работать. А в реальности она может и не найтись...

 
 
 
 Re: проблемы с выделением памяти
Сообщение08.09.2024, 00:11 
Аватара пользователя
TheRuinedMap

TheRuinedMap в сообщении #1653694 писал(а):
. А в реальности она может и не найтись...


...и прислать SIGKILL. Тогда как в условии SIGSEGV. Вы невнимательны к симптомам, коллега.

 
 
 
 Re: проблемы с выделением памяти
Сообщение08.09.2024, 13:38 
Вообще, там не всё так однозначно, если проверить доступную память после и до выделения с помощью info.freeram ,
то результат не меняется, но меняется после того как в выделенную память начнут записываться данные. Это наверное тоже может привести к проблемам

 
 
 
 Re: проблемы с выделением памяти
Сообщение08.09.2024, 14:59 
Missir
Это не проблема, а особенность работы ОС с памятью. Выделяйте с флагом инициализации (или инициализируйте сами если в API флага не предусмотрено), будет дольше, зато память реально выделится. А без него память не выделяется, а резервируется, без физического выделения, которое происходит только по мере записи в страницы (и переносит тормоза из начала во внутренние циклы, размазывая и по ним, и по времени работы, которое суммарно увеличивается незначительно (но бывают и исключения), лишь перераспределяется между кусками кода). ОС любит экономить физическую память и это один из её механизмов.
Особенно это хорошо видно на примере выделения большого куска памяти в локальном стеке, не просто sub RSP,d, а потом ещё и пишут туда с шагом 4K неважно что, иначе ОС реально физическую память не выделит.
Собственно TheRuinedMap объяснил ровно это же самое.
Насколько это применимо к конкретной версии линукса я не в курсе.
Видимо Вам пришла пора почитать что-то более глубокое о работе своей ОС, раз стали (не в первый раз) натыкаться на особенности её работы и принимать это за глюки/проблемы.

 
 
 
 Re: проблемы с выделением памяти
Сообщение13.10.2024, 16:12 
Аватара пользователя
Эта особенность связанна с работой со свопом, когда его размер определяется системой. В случае, когда своп близок к завершению, система его предупреждающе увеличивает, но этот процесс условно асинхронный относительно вызовов приложений по выделению памяти - соответственно, иногда система может не успевать, и выделение памяти может фейлиться.

Ошибка у вас возникает при обращении к памяти, а не при ее как вам кажется выделении, т.к. реальное выделение памяти (commit), происходит при обращении к выделенному (reserved) адресному пр-ву. При выделении маленьких блоков это не проявляется, т.к. внутри вашего приложения между malloc и системой еще есть прилинкованный посредник - менеджер памяти - он выделяет и память у системы большими блоками и нарезает внутри приложения на маленькие. Что бы этого избежать, можно использовать более низкоуровневое ОС-зависимое API, чем malloc/release. В случае Windows это VirtualAlloc/Protect/Free. В случае Linux - это mmap/madvise/mprotect. Или костыль, как написали выше - после выделения пробежаться с шагом 4K (одной страницы) по выделенной памяти и наследить (это неэффективно с точки зрения использования физической памяти, но значительно проще).

Сама проблема лечится фиксированием минимального размера свопа, поставьте x2 от размера ОЗУ. Также лечится использованием вышеупомянутых ОС-зависимых API, но в цикле (например, пытаться выделять reserve+commit память 10 раз с периодом в 100 мс, а потом уже осознанно падать с занесением в журналы) - тоже костыль, но работает хорошо.

 
 
 [ Сообщений: 15 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group