Стратегия отладки, чтобы найти причину bad_alloc - PullRequest
35 голосов
/ 20 марта 2010

У меня довольно серьезная ошибка в моей программе - случайные вызовы new () выдают bad_alloc.

Из документации, которую я могу найти на bad_alloc, похоже, что она выброшена по следующим причинам:

  1. Когда на компьютере не хватает памяти (что определенно не происходит, у меня есть 4 ГБ ОЗУ, программа выдает bad_alloc при использовании менее 5 МБ (проверено в диспетчере задач), когда в фоновом режиме ничего серьезного не происходит). 1007 *

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

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

Однако приложение, которое я запускаю, запускает более одного потока, что может способствовать возникновению проблемы. При тестировании всех объектов в одном потоке все работает нормально. Единственная другая вещь, о которой я могу думать, это то, что здесь происходит, может быть какое-то состояние гонки, вызванное вызовом new () более чем в одном месте одновременно, но я попытался добавить мьютексы, чтобы предотвратить это поведение. без эффекта.

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

Я использую Microsoft Visual Studio 2008 с Poco для многопоточности.

Ответы [ 5 ]

23 голосов
/ 20 марта 2010

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

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

Кроме того, я должен отметить, что 32-разрядный процесс в Windows имеет максимум 2 ГБ адресного пространства (3 ГБ для программ, поддерживающих большие адреса). Это независимо от того, сколько оперативной памяти вы установили, виртуальная память не выделяется, и выделение ресурсов не прекращается, пока вы не исчерпаете адресное пространство, даже если у вас всего 1 ГБ оперативной памяти.

Вот хорошее обсуждение повреждения памяти в C ++ http://www.eventhelix.com/RealtimeMantra/Basics/debugging_software_crashes_2.htm

21 голосов
/ 20 марта 2010

Другая возможная проблема заключается в том, что, хотя вы упоминаете, что программа использует менее 5 МБ, вы не упоминаете, сколько места она пытается выделить. У вас может быть некоторое состояние гонки, которое искажает значение, которое вы используете для определения размера выделения, и оно может пытаться выделить 37 ТБ или что-то в этом роде.

Полагаю, не особо вероятно, но стоит проверить.

3 голосов
/ 20 марта 2010

Несколько уточнений:

Каждый процесс в Windows получает 4 ГБ виртуальной памяти, из которых 2 ГБ предназначены для пользовательского пространства, а оставшиеся - для ядра. 4 ГБ ОЗУ не будут использоваться для виртуальной памяти, но для физической памяти.

В 2 ГБ памяти все EXE, DLL загружаются и вряд ли 1,6 - 1,7 ГБ доступны для выделения памяти. В этой памяти, если нет непрерывной памяти для выделения, выделение памяти завершается неудачей.

1 голос
/ 29 августа 2013

У меня действительно была эта проблема раньше, и она была устранена путем очистки и перестройки проекта. Всегда стоит попробовать, когда у вас странное поведение (если это не огромный проект, который компилируется часами).

1 голос
/ 03 апреля 2010

bad_alloc может быть также сгенерирован другим кодом.

Я видел, как он используется ограниченным пулом памяти, предназначенным для использования с контейнерами STL. Когда был достигнут предел размера, он бросил bad_alloc, и программное обеспечение просто должно было его обработать.

...