linux новый / удалить, malloc / освободить большие блоки памяти - PullRequest
3 голосов
/ 29 марта 2010

У нас есть система linux (kubuntu 7.10), которая запускает несколько процессов сервера CORBA. Программное обеспечение сервера использует библиотеки glibc для выделения памяти. Линукс ПК имеет 4G физической памяти. Своп отключен по соображениям скорости.

При получении запроса на обработку данных один из процессов сервера выделяет большой буфер данных (используя стандартный оператор C ++ 'new'). Размер буфера варьируется в зависимости от ряда параметров, но обычно составляет около 1,2 Гбайт. Это может быть до 1,9 Гбайт. Когда запрос завершен, буфер освобождается с помощью «delete».

Это прекрасно работает для нескольких последовательных запросов, которые выделяют буферы одинакового размера, или если запрос выделяет меньший размер, чем предыдущий. Память, кажется, свободна, все в порядке - иначе попытки выделения буфера в конечном итоге потерпят неудачу после пары запросов. В любом случае мы можем видеть, как буферная память выделяется и освобождается для каждого запроса с использованием таких инструментов, как KSysGuard и т. Д.

Проблема возникает, когда для запроса требуется буфер больше, чем предыдущий. В этом случае оператор new создает исключение. Это как если бы память, которая была свободна от первого выделения, не может быть перераспределена, даже если имеется достаточно свободной физической памяти.

Если я убью и перезапущу процесс сервера после первой операции, то второй запрос на больший размер буфера будет успешным. то есть уничтожение процесса, по-видимому, полностью освобождает освобожденную память обратно в систему.

Может ли кто-нибудь объяснить, что здесь может происходить? Может ли это быть проблема размера таблицы фрагментации или отображения? Я подумываю заменить new / delete на malloc / free и использовать mallopt для настройки способа освобождения памяти в системе.

Кстати, я не уверен, имеет ли это отношение к нашей проблеме, но сервер использует Pthreads, которые создаются и уничтожаются при каждом запросе обработки.

Ответы [ 3 ]

4 голосов
/ 29 марта 2010

В вашем распоряжении будет 3 Гб адресного пространства, если это 32-битный компьютер - 1 Гб зарезервировано для ядра. Из-за этого довольно много адресного пространства будет занимать совместно используемые библиотеки, exe-файл сегмент данных и т. д. Вы должны посмотреть на /proc/pid/maps, чтобы увидеть, как распределено адресное пространство.

Трудно сказать, сколько доступно физического адресного пространства, все системные процессы, ядро ​​и другие ваши процессы будут поглощены этим. Если предположить, что их сумма не превышает 1 ГБ, у вас все еще будет доступный 3Gb.

То, что может происходить, это фрагментация:

0Gb                                                     3Gb
---------------------~------------------------------------
|Stuff | Heap,1.2Gb allocated stuff | free heap   | Stack|
---------------------~------------------------------------

Затем вы освобождаете большой объект, но между какой-то другой памятью выделено, оставляя вас с этим:

0Gb                                                         3Gb
---------------------~------------------------------------------
|Stuff | Heap,1.2Gb free |small object(s) | free heap   | Stack|
---------------------~------------------------------------------

Если вы попытаетесь выделить объект большего размера, он не уместится в свободном пространстве 1,2 ГБ. И может не поместиться в пространство free heap, так как для этого может не хватить места.

Если вы интенсивно используете стек, это может быть рост стека и использование пространства, в противном случае можно использовать пространство кучи - хотя по умолчанию большинство дистрибутивов ограничивают стек до 8-10 МБ.

Использование malloc / realloc не поможет. Однако, если вы знаете размер самого большого нужного вам объекта, вы можете зарезервировать его при запуске. Эта часть никогда не должна быть свободна, удалена / удалена, она должна быть просто использована повторно. Трудно сказать, приведет ли это к другим неприятностям в другом месте - пространство, доступное для других объектов, уменьшится.

0 голосов
/ 30 марта 2010

Вам не хватает адресного пространства, поэтому нет единого фрагмента, достаточно большого, чтобы удовлетворить ваше выделение.

Исправление - запуск 64-битной операционной системы - в конце концов, это 21-й век!

Конечно, вам нужно будет повторно протестировать ваши приложения на 64-битную совместимость (и перекомпилировать и т. Д.), Но это имеет смысл в долгосрочной перспективе. В наши дни 4G - это не много оперативной памяти для сервера; довольно скромный имеет 16-32G.

0 голосов
/ 30 марта 2010

Большое спасибо за ответ. Дальнейшие исследования показывают, что фрагментация действительно является проблемой. Резервирование самого большого буфера, который нам когда-либо понадобится при поступлении первого запроса, и сохранение этого буфера для последующих запросов, похоже, работает.

...