Когда может произойти утечка памяти?
Я не знаю, что тут думать...
У нас есть компонент, который работает как служба. Он отлично работает на моей локальной машине, но на какой-то другой машине (на обеих машинах оперативная память равна 2 ГБ) он начинает генерировать исключения bad_alloc на второй и последующие дни. Дело в том, что использование памяти процесса остается неизменным примерно на уровне 50 МБ. Другая странная вещь заключается в том, что с помощью трассировки сообщений мы локализовали исключение, которое будет выброшено из a объект stringstream, который вставляет в поток не более 1-2 КБ данных. Мы используем STL-порт, если это имеет значение.
Теперь, когда вы получаете исключение bad_alloc, вы думаете, что это утечка памяти. Но ... все наши ручные распределения обернуты в умный указатель. Кроме того, я не могу понять, как объекту stringstream не хватает памяти, когда весь процесс использует только ~50 МБ (использование памяти остается приблизительно постоянным(и, конечно, не растет) изо дня в день).
Я не могу предоставьте вам код, потому что проект действительно большой, и часть, которая создает исключение, на самом деле ничего не делает, кроме как создает stringstream и
Итак, мой вопрос... Как может произойти утечка памяти / bad_alloc, когда процесс использует только 50 Мб памяти из 2 ГБ ? Какие еще дикие догадки у вас есть относительно того, что может быть не так?
Заранее спасибо, я знаю, что вопрос расплывчатый и т. д.- Я просто в отчаянии, и я старался изо всех сил. объясните, в чем проблема.
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 для неудачного поиска), это возможно.