что делать при сбое выделения памяти new (nothrow) в c ++ на linux

в контексте без исключения я видел несколько сообщений, говорящих

Thing* t = new(std::nothrow) Thing; // returns NULL on failure
if (!t) {
// allocation failure
}

например

Как проверить ошибки выделения памяти с новым оператором?

Как узнать возвращаемое значение, если мой C ++ «новый» сбой выделения памяти?

Я считаю, что это утверждение, которое они получили из стандартов C ++, как указано:

Если функция распределения объявлена ​​без броска
Спецификация исключения, он возвращает ноль, чтобы указать на сбой
выделите память и ненулевой указатель в противном случае.

Тем не менее, Херб Саттер
http://www.gotw.ca/publications/mill16.htm

Linux будет перегружать память, и это не соответствует стандартам c ++. то есть проверка null не относится к системе linux.
«new» либо завершается успешно, либо завершается неудачно с процессом, убитым linux.

Так что мы можем сделать? Кажется, нет способа проверить сбой.

[ОБНОВЛЕНИЕ] о Linux overcommit: overcommit_memory

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

2

Решение

По умолчанию Linux не перегружен. Реальное решение не состоит в том, чтобы настроить это так.

Вы не можете получить свой торт и съесть его тоже. Если вы используете linux в его состоянии по умолчанию (без чрезмерной загрузки), то нет проблем с обнаружением ошибки выделения памяти. Если вы сконфигурируете его для overcommit, то вам нужно либо спроектировать вашу программу так, чтобы она не могла исчерпать память (т.е. убедиться, что доступно больше памяти, чем ваша программа когда-либо будет пытаться выделить), либо перестроить вашу программу так, чтобы она заканчивалась до того, как произойдет сбой. имеют нежелательные последствия (например, не уничтожение объектов и сохранение состояния в файл).

Однако ….. если вы настаиваете на настройке вашей системы для перегрузок, то Херб как бы намекает на решение по этой ссылке.

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

  p = new (nothrow) Thing;
if (p != NULL)
touch(p);
else
terminate_with_prejudice()

где touch() гарантирует выделение памяти под Linux (страница Хербса описывает, как это сделать).

В качестве альтернативы, для бросания нового;

  try
{
p = new Thing;
touch(p);
}
catch (...)
{
terminate_with_prejudice()
}

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

Разница в том, как происходит сбой в разных системах. В обеих формах система Linux всегда будет вызывать touch() и программа будет работать неправильно при сбое. В не Linux-системе, terminate_with_prejudice() будет вызван в случае отказа. В любом случае, программа остановится.

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

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

1

Другие решения


По вопросам рекламы [email protected]