Является ли "Недостаточно памяти" исправимой ошибкой? - PullRequest
75 голосов
/ 02 декабря 2008

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

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

Какой веский аргумент в пользу того, чтобы сделать его исправимой ошибкой?

Ответы [ 23 ]

1 голос
/ 04 января 2009

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

Я привожу только этот пример, чтобы показать, что это можно сделать.

Проблема работы с OOM действительно зависит от вашей программы и среды.

Например, во многих случаях место, где происходит OOM, скорее всего, НЕ лучшее место для реального восстановления после состояния OOM.

Теперь пользовательский распределитель может работать как центральная точка в коде, который может обрабатывать OOM. Распределитель Java выполнит полный сборщик мусора до того, как он фактически выдаст исключение OOM.

Чем более «известно приложению» о вашем распределителе, тем лучше он будет использоваться в качестве центрального обработчика и агента восстановления для OOM. Снова используя Java, его распределитель не особенно осведомлен о приложении.

Это то, где что-то вроде Java легко разочаровывает. Вы не можете переопределить распределитель. Таким образом, хотя вы можете перехватывать исключения OOM в своем собственном коде, ничто не говорит о том, что какая-то используемая вами библиотека правильно перехватывает или даже правильно перебрасывает исключение OOM. Создать класс, который навсегда разрушен исключением OOM, тривиально, поскольку для некоторого объекта задано значение NULL и «этого никогда не случится», и его невозможно восстановить.

Итак, да, OOM можно восстановить, но это может быть ОЧЕНЬ сложно, особенно в современных средах, таких как Java, и изобилие сторонних библиотек различного качества.

1 голос
/ 02 декабря 2008

В общем случае это не подлежит восстановлению.

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

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

1 голос
/ 04 января 2009

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

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

0 голосов
/ 04 января 2012

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

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

0 голосов
/ 13 января 2010

uClibc имеет внутренний статический буфер объемом 8 байтов или около того для файлового ввода-вывода, когда больше нет памяти для динамического выделения.

0 голосов
/ 10 ноября 2009

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

Я не вижу, как добиться этого в многопоточном приложении. Как узнать, какой поток на самом деле отвечает за ошибку нехватки памяти? Один поток может постоянно выделять новую память и иметь gc-корни для 99% кучи, но первое неудачное выделение происходит в другом потоке.

Практический пример: всякий раз, когда я сталкивался с ошибкой OutOfMemoryError в нашем Java-приложении (работающем на сервере JBoss), это не значит, что один поток умирает, а остальная часть сервера продолжает работать: нет, есть несколько OOME, убив несколько потоки (некоторые из которых являются внутренними потоками JBoss). Я не понимаю, что я, как программист, мог бы сделать, чтобы оправиться от этого - или даже, что JBoss мог сделать, чтобы оправиться от этого. На самом деле, я даже не уверен, что вы МОЖЕТЕ: javadoc для VirtualMachineError предполагает, что JVM может быть «сломана» после того, как выдается такая ошибка. Но, возможно, вопрос был более нацелен на языковой дизайн.

0 голосов
/ 07 августа 2009

У меня есть это:

void *smalloc(size_t size) {
  void *mem = null; 
  for(;;) {
   mem = malloc(size);
   if(mem == NULL) {
    sleep(1);
   } else 
     break;
  }
  return mem;
}

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

0 голосов
/ 18 мая 2009

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

Если у вас недостаточно памяти, но может появиться что-то вроде сборщика мусора и освободить память, которую вы еще не умерли.

Другая проблема - фрагментация. Хотя у вас может быть недостаточно памяти (фрагментировано), вы все равно не сможете выделить тот огромный кусок, который вам нужен.

0 голосов
/ 21 февраля 2009

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

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

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

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

Мои два цента: -)

0 голосов
/ 03 февраля 2009

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

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