Когда может произойти утечка памяти? - PullRequest
11 голосов
/ 22 ноября 2010

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

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

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

Я не могу предоставить вам код, потому что проект действительно большой, и часть, которая вызывает исключение, на самом деле ничего не делает, кроме как создает поток строк и << некоторые данные, а затем регистрирует их. </p>

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

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

Ответы [ 8 ]

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

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

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

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

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

4 голосов
/ 22 ноября 2010

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

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

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

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

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

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

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

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

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

, когда SIZE - большое число.

Решениедолжен был выделить новый оператор

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

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

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

Tom

0 голосов
/ 23 июля 2012
 ~className(){

 //delete stuff in here

}
0 голосов
/ 24 июня 2012

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

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

0 голосов
/ 22 ноября 2010

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

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

0 голосов
/ 22 ноября 2010

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

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

Просто мой2 (евро) карат ...

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

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

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

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

2.со знаком или без знака?

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

char * p = new char[i] ;

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

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

...