утечка памяти из потока

У меня есть класс С++, который записывает свои данные в двоичный файл std::ofstream. Класс хранит данные как boost:shared_array, но я устранил это как проблему. Проблема заключается в вызове write() на ofstream.

Проблема в том, что это, кажется, утечка памяти. Система, на которой он работает, — CentOS 64bit, GCC 4.1.2.

При просмотре top и free во время работы приложения сам исполняемый файл не продолжает потреблять память (как подтверждается профилировщиком памяти в Netbeans), но объем свободной системной памяти со временем уменьшается. Более того, когда приложение завершает работу, эта память не освобождается!

Это особая проблема, потому что цель состоит в том, чтобы непрерывно записывать на диск со скоростью около 50 МБ / с в течение нескольких часов подряд. Однако, как только мы получаем около 90 МБ свободной системной памяти, кажется, что она «стабилизируется» и больше не сокращается, и приложение продолжает работать нормально. Однако это портит систему для других запущенных процессов, что плохо, ммкей.

Ниже приведена слегка упрощенная версия класса, вызывающего горе.

class WritableMessage
{
public:
    WritableMessage();
    void write(std::ofstream* const idxStream, std::ofstream* const dataStream);

private:
    IdxRecord m_idx;
    boost::shared_array<char> m_data;
};

Потоки ofstream инициализируются и уничтожаются в другом месте, но по существу они остаются открытыми для записи «навсегда».

void WritableMessage::write(std::ofstream* const idxStream, std::ofstream* const dataStream)
{
    //Call the IdxRecord to write itself (just a call to idxStream->write())
    m_idx.write(idxStream, dataStream->tellp());

    //This is the main issue, because this data can be up to about 2MB in size
    //for each write.  Commenting out this line removes all issues with the memory leak
    dataStream->write(m_data.get(), m_idx.getMessageSize());

    //I'd expect the flush to clear any buffers that the ofstream maintains,
    //but apparently not
    idxStream->flush();
    dataStream->flush();
}

person fwg    schedule 21.06.2011    source источник
comment
Если она не восстанавливается при смерти процесса, это не память процесса. Может быть, это дисковый кеш, выделенный ОС? Тот факт, что он использует память только до определенного объема, похоже, также указывает на это.   -  person sbi    schedule 21.06.2011
comment
when the application is running the executable itself does not continue to consume memory (as backed up by the memory profiler in Netbeans), but the amount of free system memory does decrease over time. What's more, when the application exits this memory is not reclaimed! Весьма подозрительно.   -  person Lightness Races in Orbit    schedule 21.06.2011
comment
Используйте течеискатель для определения утечек. валгринд приходит на ум   -  person sehe    schedule 21.06.2011


Ответы (2)


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

person Vitor    schedule 21.06.2011
comment
Это действительно очень странно или, по крайней мере, сбивает с толку. Особенно с учетом того, что после того, как ofstream выполнил запись, я никогда не открываю файл для ввода с помощью ifstream, поэтому нет необходимости кэшировать что-либо после записи на диск. И то, что он не освобождает память после того, как программа существует, выглядит просто неправильно. Я заметил, что повторный запуск программы освобождает кеш, мгновенно возвращая мне память, прежде чем снова ее съесть. - person fwg; 22.06.2011
comment
Система не может знать заранее, что никто не будет использовать записанные данные. Поскольку он уже находится в ОЗУ, когда вы записываете, вы можете просто сохранить его в надежде, что он может быть полезен в будущем. - person Vitor; 22.06.2011

Используйте vmstat (справочная страница)

vmstat -S m 1

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

Я могу легко показать эффект на моем рабочем столе 8GB (linux), войдя в систему и просто выполнив 'dd if=/dev/sda of=/dev/null'; буферная память будет постоянно потреблять всю доступную память.

Это по дизайну

Некоторые соответствующие ссылки:

person sehe    schedule 21.06.2011
comment
Спасибо, я вижу это и вижу, что при необходимости он восстанавливается. Есть ли способ освободить кеш при выходе из программы или при закрытии ofstreams? Я не думаю, что объяснять клиенту, почему наше приложение на самом деле не использует 99% доступной памяти, несмотря на все признаки того, что это слишком просто! - person fwg; 22.06.2011
comment
Это не проблема. Просто укажите им документацию для их дистрибутива Linux. Научите их отслеживать фактическое использование памяти в файле top/htop. Если вы настаиваете: echo 1 > /proc/sys/vm/drop_caches (echo 3 удалить страницы, inode и кэши dentry). Теперь вам нужно запустить это как root (ick!). Конечно вы понимаете, что у вас должно быть больше проблем с объяснением, почему вам нужно запускать ваше приложение от root (только для того, чтобы: (а) косметически подделать простые мемстаты (б) мусорить производительность сервера за счет уничтожения полезного кеша!) - person sehe; 22.06.2011
comment
На самом деле мы отслеживаем использование памяти с помощью SNMP, который просто сообщает об использовании как 99%. - person fwg; 23.06.2011
comment
@fwgx: вы делаете это неправильно :) исправьте мониторинг. Честно говоря, я надеюсь, что ваше программное обеспечение для мониторинга на самом деле поддерживает что-то более разумное, чем метрика, которую оно дает прямо сейчас :) - person sehe; 23.06.2011