Каковы шансы, что RealLoc должен потерпеть неудачу? - PullRequest
9 голосов
/ 07 февраля 2011

Сбой, когда заканчивается свободное пространство, похожее на malloc, или могут быть другие причины?

Ответы [ 4 ]

11 голосов
/ 07 февраля 2011

Любая из функций выделения (malloc, realloc, calloc и в POSIX, posix_memalign) может завершиться ошибкой по любой из следующих причин и, возможно, по другим:

  • Вы израсходовали все свое виртуальное адресное пространство или, по крайней мере, его полезную часть. На 32-разрядной машине существует только 4 ГБ адресов, и, возможно, 1 ГБ или около того зарезервировано для использования ядром ОС. Даже если ваша машина имеет 16 ГБ физической памяти, один процесс не может использовать больше, чем у него есть адреса.
  • Вы не израсходовали свое виртуальное адресное пространство, но вы настолько сильно его фрагментировали, что нет доступного непрерывного диапазона адресов запрошенного размера. Это может произойти (на 32-разрядной машине), если вы успешно выделите 6 512 МБ блоков, освободите каждый второй, а затем попытаетесь выделить 1 ГБ блок. Конечно, есть много других примеров с меньшим объемом памяти.
  • Ваша машина исчерпала физическую память, либо из-за того, что ваша программа использовала все это, либо из-за того, что другие программы, работающие на машине, использовали все это. Некоторые системы (Linux в конфигурации по умолчанию) будут overcommit , что означает, что malloc не прекратит работу в этой ситуации, но вместо этого ОС позже убьет одну или несколько программ, когда обнаружит, что на самом деле недостаточно физического память обойти. Но в надежных системах (включая Linux с отключенной избыточной передачей) malloc завершится ошибкой, если не останется физической памяти.

Обратите внимание, что, строго говоря, функциям распределения разрешается отказывать в любое время по любой причине. Минимизация ошибок - это проблема качества реализации. Также возможно, что realloc может потерпеть неудачу, даже если уменьшит размер объекта; это может происходить в реализациях, которые строго разделяют распределение по размеру. Конечно, в этом случае вы можете просто продолжать использовать старый (больший) объект.

4 голосов
/ 07 февраля 2011

Вы должны думать о realloc как о работе следующим образом:

void *realloc(void *oldptr, size_t newsize)
{
   size_t oldsize = __extract_size_of_malloc_block(oldptr);
   void *newptr = malloc(newsize);

   if (!newptr)
     return 0;

   if (oldsize > newsize)
     oldsize = newsize;

   memcpy(newptr, oldptr, oldsize);
   free(oldptr);
   return newptr;
}

Реализация может быть в состоянии выполнять конкретные случаи более эффективно, чем эта, но реализация, которая работает точно так, как показано, является на 100% правильной. Это означает, что realloc(ptr, newsize) может потерпеть неудачу в любое время malloc(newsize) потерпит неудачу; в частности, может произойти сбой , даже если вы сокращаете выделение .

Теперь в современных настольных системах есть веские основания не пытаться восстанавливаться после сбоев malloc, а вместо этого включать malloc в функцию (обычно называемую xmalloc), которая немедленно завершает программу, если malloc терпит неудачу; естественно, тот же аргумент применим к realloc. Дело в том:

  1. Настольные системы часто работают в режиме «overcommit», когда ядро ​​с радостью раздаст больше адресного пространства, чем может быть поддержано RAM + swap, при условии, что программа фактически не собирается использовать все это. Если программа попытается использовать все это, она будет принудительно завершена. В таких системах malloc завершится с ошибкой только в том случае, если вы исчерпали адресное пространство , что маловероятно в 32-разрядных системах и почти невозможно в 64-разрядных системах.
  2. Даже если вы не находитесь в режиме overcommit, существует вероятность того, что настольная система имеет так много оперативной памяти и доступно для подкачки, что задолго до того, как вы вызовете сбой malloc, пользователю надоест его диск-диск и принудительно завершить вашу программу.
  3. Нет практического способа проверить восстановление после сбоя выделения; даже если бы у вас была библиотека подкладок, которая могла бы точно контролировать, какие вызовы на malloc были неудачными (такие подкладки в лучшем случае сложно, в худшем случае невозможно создать, в зависимости от ОС), вам придется протестировать порядок 2 N. шаблоны ошибок, где N - количество вызовов malloc в вашей программе.

Аргументы 1 и 2 не применяются к встроенным или мобильным системам (пока!), Но аргумент 3 все еще действует там.

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

1 голос
/ 07 февраля 2011

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

И не забудьте освободить указатель old , который вы пытались перераспределить.

ptr=realloc(ptr,10);

- ВСЕГДА возможная утечка памяти.

Всегда делайте это так:

void *tmp=ptr;
if(ptr=realloc(ptr,10)==NULL){
  free(tmp);
  //handle error...
}
0 голосов
/ 07 февраля 2011

У вас есть два вопроса.

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

В случае сбоя realloc и malloc почти равны.Единственная причина, по которой realloc может завершиться ошибкой, заключается в том, что вы даете ему неверный аргумент, то есть память, которая не была выделена с помощью malloc или realloc или которая ранее была free d.

Редактировать: С учетом комментария Р.Да, вы можете настроить свою систему так, чтобы она не работала при выделении ресурсов.Но, во-первых, AFAIK, это не по умолчанию.Для этого необходимо настроить привилегии, и как программист приложения вы не можете рассчитывать на это.Во-вторых, даже если у вас есть система, настроенная таким образом, она выдаст ошибку только тогда, когда ваше доступное пространство подкачки будет израсходовано.Обычно ваша машина будет недоступна задолго до этого: она будет выполнять механические вычисления на вашем жестком диске (замена АКА).

...