Как уменьшить потребление памяти C ++ по умолчанию? - PullRequest
15 голосов
/ 14 ноября 2010

У меня есть серверное приложение, написанное на C ++. После запуска он использует около 480 КБ памяти на Linux x86 (Ubuntu 8.04, GCC 4.2.4). Я думаю, что 480 КБ - это избыточный объем памяти: сервер еще ничего не делает, к нему не подключены клиенты. (См. Также мой комментарий ниже, в котором я объясняю, почему я думаю, что 480 КБ - это много памяти.) Единственное, что сервер делает во время инициализации, это порождает один или два потока, настраивает несколько сокетов и другие простые вещи, которые не требуют большого объема памяти.

Обратите внимание, что я говорю о реальном использовании памяти, а не о размере виртуальной машины. Я измерил его, запустив 100 экземпляров моего сервера на простаивающем ноутбуке и измерив использование системной памяти с помощью «free» до и после запуска экземпляров сервера. Я уже учел кеш файловой системы и тому подобное.

После некоторого тестирования может показаться, что что-то во время выполнения C ++ заставляет мой сервер использовать столько памяти, даже если сам сервер ничего не делает. Например, если я вставлю

getchar(); return 0;

сразу после

int main(int argc, char *argv[]) {

тогда использование памяти по-прежнему составляет 410 КБ на экземпляр!

Мое приложение зависит только от Curl и Boost. У меня достаточно опыта в программировании на C, и я знаю, что библиотеки C не имеют тенденцию увеличивать потребление памяти, пока я их не использую.

Другие вещи, которые я нашел:

  • Простое приложение hello world C потребляет около 50 КБ памяти.
  • Простое приложение hello world C, связанное с Curl, но не использующее Curl, также потребляет около 50 КБ памяти.
  • Простое приложение C ++ (без Boost) для hello world потребляет около 100 КБ памяти.
  • Простое приложение C ++ hello world, которое включает некоторые заголовки Boost, но на самом деле не использует Boost, потребляет около 100 КБ памяти. Нет символов Boost при проверке исполняемого файла с помощью «nm».

Поэтому мой вывод таков:

  1. Gcc выбрасывает неиспользуемые символы повышения.
  2. Если мое приложение использует Boost, , то что-то во время выполнения C ++ (возможно, динамический компоновщик) заставляет его использовать много памяти. Но что? Как мне узнать, что это за вещи, и что я могу с ними сделать?

Я помню несколько обсуждений KDE несколько лет назад о проблемах динамического компоновщика C ++. Динамический компоновщик Linux C ++ тогда вызывал медленное время запуска в приложениях KDE C ++ и большое потребление памяти. Насколько я знаю, эти проблемы были исправлены в C ++. Но может ли нечто подобное быть причиной чрезмерного потребления памяти, которое я вижу?

Ответы от экспертов gcc / dynamic linking очень ценятся.

Для тех, кому интересно, рассматриваемый сервер - агент регистрации Phusion Passenger: https://github.com/FooBarWidget/passenger/blob/master/ext/common/LoggingAgent/Main.cpp

Ответы [ 3 ]

5 голосов
/ 14 ноября 2010

Среда выполнения C выделяет больше памяти, чем ваш процесс фактически использует как часть нормальной работы. Это связано с тем, что выделение памяти на уровне ядра происходит крайне медленно и может быть выполнено только в блоках размером страницы (размер страницы обычно составляет 4 КБ на блоках x86, но может быть больше и обычно составляет 8 КБ или более на машинах x 64).

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

Наконец, если вы используете положительные бонусы, они, вероятно, зависят от некоторых компонентов STL, таких как std::vector. Эти компоненты выделяют пространство для элементов, используя std::allocator<T>, что в некоторых случаях снова выделит больше места, чем фактически используется. (В частности, основанные на узлах структуры, такие как std::map, std::set и std::list, обычно делают это, чтобы объединить узлы списка или дерева на одной странице памяти)

Короче говоря: не беспокойтесь об этом. Пол-мегабайта памяти не так уж много для любого воображения (по крайней мере, в настоящее время), и большая часть этого, вероятно, просто амортизирует использование функций динамического распределения. Запишите свой реальный сервер, и, если он использует слишком много памяти, ТОГДА поищите способы уменьшить использование памяти.

РЕДАКТИРОВАТЬ: Если компонент boost, который вы используете, оказывается asio, и вы используете сокеты, вы должны также знать, что используется некоторая память, чтобы поддерживать буферы для сокетов.

1 голос
/ 14 ноября 2010

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

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

Кстати, prelink также было исправлением для KDE.

1 голос
/ 14 ноября 2010

Один из способов уменьшить потребление памяти - это уменьшить размер стека потоков.

Что касается boost , как прокомментировал Стив Джессоп , вы должны быть немного болееспецифичнее, чем «буст».

...