Каковы стратегии обработки нехватки памяти в программировании на C? - PullRequest
6 голосов
/ 13 августа 2010

Одной из стратегий, которую я сам себе выделил, является выделение 5 мегабайт памяти (или любого необходимого вам числа) при запуске программы.

Затем, когда в любой момент программа malloc() возвращает NULL, выосвободите 5 мегабайт и снова вызовите malloc(), что завершится успешно и программа продолжит работу.

Что вы думаете об этой стратегии?

А какие еще стратегии вы знаете?

Спасибо, Бода Чидо.

Ответы [ 9 ]

13 голосов
/ 13 августа 2010

Обрабатывать сбои malloc, грациозно завершая работу. С современными операционными системами, файлами подкачки и т. Д. Вы никогда не должны заранее готовиться к сбоям памяти, просто выходите изящно. Маловероятно, что вы когда-либо столкнетесь с ошибками нехватки памяти, если у вас нет алгоритмической проблемы.

Кроме того, выделение 5 МБ без причины при запуске является безумным.

5 голосов
/ 13 августа 2010

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

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

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

Надеюсь, это поможет.

2 голосов
/ 13 августа 2010

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

void *smalloc(size_t size) {
   for(int i = 0; i < 100; i++) {
      void *p = malloc(size);
      if(p) 
        return p;
      sleep(1);
    }
   return NULL;
}

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

2 голосов
/ 13 августа 2010

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

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

1 голос
/ 13 августа 2010

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

Но реальная проблема заключается в том, что вы не знаете , почему выисчерпал пространство виртуальной памяти.И если вы не знаете, почему, то вы ничего не можете сделать, чтобы предотвратить слишком быстрое потребление этой дополнительной памяти и все же сбой вашей программы с OOM.Это очень вероятно, вы уже израсходовали около двух гигабайт, эти дополнительные 5 МБ - это капля воды на горячей плите.

Любая схема, которая переводит приложение в «аварийный режим».очень непрактично.Вам придется прервать выполнение кода, чтобы вы могли прекратить, скажем, загрузку огромного файла данных.Это требует исключения.Теперь вы вернулись к тому, что у вас уже было, std :: badalloc.

1 голос
/ 13 августа 2010

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

Если вы просто собираетесь продолжать работу, нет смысла предварительно выделять резервный резервный ресурс..

1 голос
/ 13 августа 2010

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

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

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

Имейте в виду, что когда вы получаете NULL от malloc, это означает, что как у физической, так и у виртуальной памяти больше нет свободного места, а это означает, что ваша программа постоянно обменивается, что делает ее медленной и компьютер не отвечает. *

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

0 голосов
/ 13 августа 2010

Я хочу поддержать мнение о том, что подход к предварительному распределению 5 МБ является "безумным", но по другой причине: он зависит от условий гонки.Если причина исчерпания памяти находится внутри вашей программы (виртуальное адресное пространство исчерпано), другой поток может потребовать 5 Мб после того, как вы освободите его, но до того, как вы его используете.Если причиной исчерпания памяти является недостаток физических ресурсов на машине из-за того, что другие процессы используют слишком много памяти, эти другие процессы могут потребовать 5 МБ после ее освобождения (если реализация malloc возвращает пространство в систему).

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

Как мы видели в первом абзаце, из-за условий гонки вашПодход "malloc 5mb and free it" не работает.В идеале код для синхронизации данных и записи информации для восстановления должен быть полностью свободным от выделения;Если ваша программа хорошо спроектирована, она, вероятно, не требует выделения.Один из возможных подходов, если вы знаете, что на этом этапе вам потребуются выделения, - это реализовать свой собственный распределитель, работающий в небольшом статическом буфере / пуле, и использовать его во время завершения выделения при сбое распределения.

0 голосов
/ 13 августа 2010

Большинство современных ОС в конфигурации по умолчанию допускают чрезмерную загрузку памяти, поэтому ваша программа вообще не получит NULL из malloc () или, по крайней мере, до тех пор, пока она каким-то образом (по ошибке, я думаю) не исчерпает все доступное адресное пространство (не память) , А затем он записывает совершенно правильное место в памяти, получает ошибку страницы, в резервном хранилище нет страницы памяти и BANG (SIGBUS) - вы мертвы, и там нет хорошего выхода.

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

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