Когда может произойти утечка памяти?


Я не знаю, что тут думать...

У нас есть компонент, который работает как служба. Он отлично работает на моей локальной машине, но на какой-то другой машине (на обеих машинах оперативная память равна 2 ГБ) он начинает генерировать исключения bad_alloc на второй и последующие дни. Дело в том, что использование памяти процесса остается неизменным примерно на уровне 50 МБ. Другая странная вещь заключается в том, что с помощью трассировки сообщений мы локализовали исключение, которое будет выброшено из a объект stringstream, который вставляет в поток не более 1-2 КБ данных. Мы используем STL-порт, если это имеет значение.

Теперь, когда вы получаете исключение bad_alloc, вы думаете, что это утечка памяти. Но ... все наши ручные распределения обернуты в умный указатель. Кроме того, я не могу понять, как объекту stringstream не хватает памяти, когда весь процесс использует только ~50 МБ (использование памяти остается приблизительно постоянным(и, конечно, не растет) изо дня в день).

Я не могу предоставьте вам код, потому что проект действительно большой, и часть, которая создает исключение, на самом деле ничего не делает, кроме как создает stringstream и

Итак, мой вопрос... Как может произойти утечка памяти / bad_alloc, когда процесс использует только 50 Мб памяти из 2 ГБ ? Какие еще дикие догадки у вас есть относительно того, что может быть не так?

Заранее спасибо, я знаю, что вопрос расплывчатый и т. д.- Я просто в отчаянии, и я старался изо всех сил. объясните, в чем проблема.

8 11

8 ответов:

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

Вы также можете использовать Valgrind или одну из его замен Windows, чтобы найти утечку/переполнение.

Одна из вероятных причин в вашем описании заключается в том, что вы пытаетесь выделить блок какого-то неоправданно большого размера из-за ошибки в коде. Что-то вроде этого;

 size_t numberOfElements;//uninitialized
 if( .... ) {
    numberOfElements = obtain();
 }
 elements = new Element[numberOfElements];

Теперь, если numberOfElements остается неинициализированным, он может содержать какое-то неоправданно большое число, и поэтому вы эффективно пытаетесь выделить блок, скажем, 3 ГБ, что менеджер памяти отказывается делать.

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

Просто догадка,

Но у меня были проблемы в прошлом при распределении массивов как так

int array1[SIZE];  // SIZE limited by COMPILER to the size of the stack frame

Когда размер-это большое число.

Решение состояло в том, чтобы выделить новый оператор

int* array2 = new int[SIZE];  // SIZE limited only by OS/Hardware

Я нашел это очень запутанным, причиной оказался кадр стека, как обсуждается здесь в решении Мартина Йорка: существует ли ограничение максимальной длины массива в C++?

Всего наилучшего,

Том

Проверьте профиль других процессов на машине, используяProcess Explorer из sysinternals - вы получите bad_alloc, если память коротка, даже если это не вы вызываете давление памяти.

Проверьте использование собственной памяти с помощьюumdh , чтобы получить снимки и сравнить профиль использования с течением времени. Вам придется сделать это в начале цикла, чтобы избежать взрыва инструмента, но если поведение вашего процесса не ухудшается с течением времени (т. е. никакого внезапного патологического поведения) вы должен получить точную информацию об использовании его памяти в момент времени T против времени T+t.

Еще один риск: вы не говорите, в какой из трех операций возникает ошибка (построение, << или журнал), но проблема может заключаться в фрагментации памяти, а не в потреблении памяти. Возможно, stringstream не может найти непрерывный блок памяти, достаточно длинный, чтобы вместить пару КБ.

Если это так, и если вы выполняете эту функцию в первый день (без сбоев), то вы можете сделать stringstream статической переменной и повторно использовать его. Насколько мне известно stringstream не делает этого освободите его буферное пространство в течение всего срока службы, поэтому, если он установит большой буфер в первый день, он будет продолжать иметь его с тех пор (для дополнительной безопасности вы можете запустить фиктивную строку 5Kb через него, когда он будет построен впервые).

Я не понимаю, почему поток бросает. Разве у вас нет свалки неудачного процесса? Или, возможно, присоединить к нему отладчик, чтобы увидеть, что распределитель пытается выделить?

Но если вы перегрузили operator <<, то, возможно, в вашем коде действительно есть ошибка.

Только мои 2 (евро) cts...

1. Фрагментация ?

Память может быть фрагментирована.

В какой-то момент Вы пытаетесь выделить байты размера, но распределитель не находит в памяти непрерывный кусок байтов размера, а потом выкинуть bad_alloc.

Примечание: этот ответ был написан до того, как я прочитал, что эта возможность была исключена.

2. подписанные и неподписанные ?

Другой возможностью было бы использование знакового значения для размера, который будет выделен:

char * p = new char[i] ;

Если значение i отрицательно (например, -1), приведение к беззнаковому интегралу size_t заставит его выйти за пределы того, что доступно распределителю памяти.

Поскольку использование знакового интеграла довольно распространено у пользователя код, если он используется только в качестве отрицательного значения для недопустимого значения (например, -1 для неудачного поиска), это возможно.

 ~className(){

 //delete stuff in here

}

Например, утечка памяти может произойти, когда вы используете оператор new в c++ и забываете использовать оператор delete.

Или, другими словами, когда вы выделяете блок памяти и забываете освободить его.