Всегда проверять malloc'ed память? - PullRequest
21 голосов
/ 21 декабря 2009

Я часто ловлю себя на том, что делаю следующее (в некритических компонентах):

some_small_struct *ptr=(some_small_struct *) malloc(sizeof(some_small_struct));
ptr->some_member= ...;

Словом, я динамически выделяю память для небольшой структуры и использую ее напрямую, не проверяя указатель malloc. Я понимаю, что всегда есть шанс, что программа не получит запрошенную память (да!), Но учтите следующее:

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

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

Мое рассуждение вменяемое (достаточно)?

Обновлено

  1. Функция «safe_malloc» может быть полезна при отладке и может быть полезна в противном случае
  2. +X доступ может скрыть основную причину указателя NULL
  3. В Linux «оптимистичное выделение памяти» может скрывать условия OOM (Out-Of-Memory)

Ответы [ 10 ]

19 голосов
/ 21 декабря 2009

Зависит от платформы. Например, в Linux (по умолчанию) нет особого смысла проверять NULL:

http://linux.die.net/man/3/malloc

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

11 голосов
/ 21 декабря 2009

В случае C это зависит от платформы. Если вы находитесь на встроенной платформе с очень небольшим объемом памяти, вы должны всегда проверять, что вы делаете, если она терпит неудачу, сказать труднее. В современной 32-разрядной ОС с виртуальной памятью система, вероятно, перестанет отвечать на запросы и аварийно завершит работу, прежде чем допустит нехватку памяти. В этом случае, вызов таНос никогда не возвращается, поэтому утилита проверки его значения становится спорной.

В случае C ++ вы должны использовать new вместо malloc, и в этом случае будет возникать исключение при исчерпании, поэтому нет смысла проверять возвращаемое значение.

7 голосов
/ 22 декабря 2009

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

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

Но многие ошибки выделения не имеют ничего общего с нехваткой памяти. Фрагментация может привести к сбою выделения из-за недостатка доступного непрерывного пространства, даже несмотря на наличие большого количества свободной памяти. В вопросе конкретно говорится о «малой структуре», так что это, вероятно, так же плохо, как истинное состояние нехватки памяти. (Но код постоянно меняется. Какая небольшая структура сегодня может стать монстром завтра. А если она настолько мала, вам действительно нужна память из кучи или вы можете получить ее из стека?)

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

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

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

7 голосов
/ 21 декабря 2009

Я бы сказал нет. Использование указателя NULL может привести к сбою программы (вероятно).
Но обнаружив это и сделав что-то умное, все будет в порядке, и вы сможете восстановить ситуацию из-за недостатка памяти.

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

Это, конечно, проблема C, которая автоматически обрабатывается в C ++ с помощью исключений и RAII.
Поскольку new не вернет NULL, проверять нет смысла.

2 голосов
/ 21 декабря 2009

Если вы работаете в Linux / MaxOs / Windows или другой системе виртуальной памяти, то ... единственная причина для проверки возвращаемого значения из malloc - если у вас есть стратегия освобождения достаточного количества памяти, чтобы позволить программе продолжать бежать. Информационное сообщение поможет в диагностике проблемы, но только если ваша программа вызвала ситуацию нехватки памяти. Обычно это не ваша программа, и единственная вещь, которая может помочь вашей программе, - это выйти как можно быстрее.

assert(ptr != NULL);

сделает все это. Моя обычная стратегия - слой вокруг malloc, который имеет это в этом.

void *my_malloc(size_t size)
{
    void *ptr = malloc ( size );
    assert(ptr != NULL);
    return *ptr;
}

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

2 голосов
/ 21 декабря 2009

Кроме того, что если обработка нулевого указателя еще более усугубляет опасную ситуацию ??

Я не понимаю, почему это может усугубить ситуацию.
В любом случае, при написании кода для Windows ptr-> some_member будет выдавать нарушение прав доступа, поэтому вы сразу увидите проблему, поэтому я не вижу причин проверять возвращаемое значение, если только ваша программа не имеет возможности освободить память. Для платформ, которые не обрабатывают нулевые указатели хорошим способом (исключая исключение), опасно игнорировать такие точки.

2 голосов
/ 21 декабря 2009

, по крайней мере, я бы добавил туда assert(ptr != NULL), чтобы вы получили значимую ошибку.

1 голос
/ 21 декабря 2009

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

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

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

0 голосов
/ 21 декабря 2009

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

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

Кроме того, в linux память, выделенная процессу, ограничена. Попробуйте создать 1000 потоков в процессе и выделить немного памяти в каждом из них, тогда вы можете легко смоделировать состояние нехватки памяти. :)

Всегда лучше проверять возвращаемые значения sys!

0 голосов
/ 21 декабря 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...