“Из памяти” исправимая ошибка?

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

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

Кстати, я думаю, что этот аспект тестирования MT-кода здесь не упоминался: идентифицируйте инварианты кода, который вы можете проверить случайным образом. К сожалению, найти эти инварианты тоже довольно тяжелая проблема. Кроме того, они могут не занимать все время во время выполнения, поэтому вам нужно найти / обеспечить выполнение пунктов выполнения, где вы можете ожидать, что они будут истинными.

Некоторые интересные ссылки для чтения:

74
задан Walter Bright 2 December 2008 в 12:06
поделиться

22 ответа

Это действительно зависит от того, что Вы создаете.

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

36
ответ дан Jon Skeet 7 November 2019 в 07:45
поделиться

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

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

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

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

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

0
ответ дан Zuu 7 November 2019 в 07:45
поделиться

Это является просто озадачивающим меня теперь.

На работе, у нас есть пакет сотрудничества приложений, и память кончается. В то время как проблема, любой заставляют комплект приложений пойти 64-разрядный (и таким образом, быть в состоянии работать вне этих 2 Идут, ограничивает, у нас есть на нормальном Win32 ОС), и/или уменьшите наше использование памяти, эту проблему, "Как восстановиться с OOM", не выйдет из моей головы.

, Конечно, я не имею никакого решения, но все еще играю при поиске того для C++ (из-за RAII и исключений, главным образом).

, Возможно, процесс, который, как предполагают, восстановился корректно, должен сломать свою обработку в atomic/rollback-able задачах (т.е. использование только функции/методы, дающие strong/nothrow гарантия исключения) с "буфером/пулом памяти", зарезервированной для восстановления целей.

Должен один из сбоев задачи, C++ bad_alloc раскрутил бы стек, свободный некоторая память стека/"кучи" через RAII. Восстанавливающаяся функция тогда спасла бы как можно больше (сохраняющий исходные данные задачи на диске, для использования на более поздней попытке), и возможно зарегистрировала бы данные задачи для более поздней попытки.

я действительно полагаю, что использование C++ strong/nothrow guanrantees может помочь процессу выжить в условиях низкой доступной памяти, даже если это был бы сродни свопинг памяти (т.е. медленный, несколько неответ, и т.д.), но конечно, это - только теория. Я просто должен стать более умным на предмете прежде, чем попытаться моделировать это (т.е. создать программу C++ с пользовательским новым/удаленным средством выделения с ограниченной памятью, и затем попытаться сделать некоторую работу под теми напряженное условие).

Хорошо...

0
ответ дан paercebal 7 November 2019 в 07:45
поделиться

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

0
ответ дан Loren Pechtel 7 November 2019 в 07:45
поделиться

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

0
ответ дан sharptooth 7 November 2019 в 07:45
поделиться

Это восстанавливаемо, только если Вы ловите его и обрабатываете его правильно.

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

Однако во многих случаях в приложении мультипотока, OOE может также произойти на фоновом потоке (включая созданный system/3rd-party библиотекой). Это почти imposable для предсказания, и Вы можете неспособный восстановить состояние всех Ваших потоков.

4
ответ дан Dennis C 7 November 2019 в 07:45
поделиться

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

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

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

1
ответ дан Mike G. 7 November 2019 в 07:45
поделиться

Это зависит от того, что Вы подразумеваете под исчерпыванием памяти.

, Когда malloc() сбои в большинстве систем, это - потому что у Вас закончилось адресное пространство.

, Если большая часть той памяти взята cacheing, или mmap'd регионами, Вы могли бы быть в состоянии исправить часть его путем освобождения кэша или unmmaping. Однако это действительно требует, чтобы Вы знали то, что Вы используете ту память для - и поскольку Вы заметили, что или большинство программ не делает, или это не имеет значения.

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

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

1
ответ дан geocar 7 November 2019 в 07:45
поделиться

У пользователей MATLAB заканчивается память все время при выполнении арифметики с большими массивами. Например, если переменная x умещается в памяти, и они выполняют "x+1" тогда, MATLAB выделяет место для результата и затем заполняет его. Если выделение приводит ошибки MATLAB к сбою, и пользователь может попробовать что-то еще. Это было бы бедствие, если бы MATLAB вышел каждый раз, когда этот вариант использования подошел.

9
ответ дан 7 November 2019 в 07:45
поделиться

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

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

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

5
ответ дан slim 7 November 2019 в 07:45
поделиться

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

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

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

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

я не на 100% уверен, но я вполне уверен' , Код, Завершенный ' (требуемое чтение для любого почтенного разработчика программного обеспечения), покрывает это.

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

8
ответ дан Ifeanyi Echeruo 7 November 2019 в 07:45
поделиться

Нет. Из ошибки памяти от GC, не должно обычно быть восстанавливаемым в текущем потоке. (Восстанавливаемый поток (пользователь или ядро) создание и завершение должен поддерживаться хотя)

Относительно встречных примеров: я в настоящее время работаю над проектом языка программирования D, который использует платформу NVIDIA CUDA для вычисления GPU. Вместо вручную руководящей памяти GPU я создал объекты прокси усилить GC D. Таким образом, когда GPU возвращается из ошибки памяти, я работаю, полное собирают и только повышают исключение, если это перестало работать во второй раз. Но, это не действительно пример из восстановления памяти, это - больше одна из интеграции GC. Другими примерами восстановления (кэши, свободные списки, стеки/хеши без автоматического уменьшения, и т.д.) являются все структуры, которые имеют их собственные методы собирающейся/уплотняющей памяти, которые являются отдельными от GC и имеют тенденцию не быть локальными для функции выделения. Таким образом, люди могли бы реализовать что-то как следующее:

T new2(T)( lazy T old_new ) {
    T obj;
    try{
        obj = old_new;
    }catch(OutOfMemoryException oome) {
        foreach(compact; Global_List_Of_Delegates_From_Compatible_Objects)
            compact();
        obj = old_new;
    }
    return obj;
}

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

3
ответ дан 7 November 2019 в 07:45
поделиться

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

я также работал со встроенные JAVA-приложения, которые попытались управлять OOM путем принуждения сборки "мусора", дополнительно выпуска некоторых некритических объектов, как выбранные с упреждением или кэшированные данные.

основные проблемы с обработкой OOM:

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

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

, Другая важная проблема должна быть в состоянии откатывать, не инициировав еще одну ситуацию OOM. Это - что-то, чем трудно управлять на высокоуровневых языках.

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

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

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

5
ответ дан n-alexander 7 November 2019 в 07:45
поделиться

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

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

1
ответ дан Michael Borgwardt 7 November 2019 в 07:45
поделиться

Это - трудный вопрос. На первом взгляде кажется, что наличие больше памяти означает "неудачливый", но, необходимо также видеть, что можно избавиться от многих связанный с памятью материал, если Вы действительно настаиваете. Позвольте нам просто взять другими способами поврежденную функцию strtok, который с одной стороны не имеет никаких проблем с материалом памяти. Тогда возьмите в качестве дубликата g_string_split из библиотеки Glib, которая в большой степени зависит от выделения памяти как, почти все в бойком или GObject основывало программы. Можно определенно сказать в более динамическом выделении памяти языков, намного более используется в качестве на большем количестве негибких языков, особенно C. Но давайте посмотрим альтернативы. Если Вы только заканчиваете программу, если у Вас заканчивается память, даже осторожный разработанный код может прекратить работать. Но если у Вас есть исправимая ошибка, можно делать с этим что-то. Так аргумент, делая это восстанавливаемый означает, что можно принять решение "обработать" ту ситуацию по-другому (например, откладывание блока памяти для чрезвычайных ситуаций или неисправности к меньшей памяти обширная программа).

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

Отношения

0
ответ дан Friedrich 7 November 2019 в 07:45
поделиться

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

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

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

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

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

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

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

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

1
ответ дан Will Hartung 7 November 2019 в 07:45
поделиться

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

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

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

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

[РЕДАКТИРОВАНИЕ] Примечание, что я работаю под предположением здесь, что Вы дали приложение, установленная сумма памяти и этой суммы меньше, чем общая доступная память, исключая область подкачки. Если можно выделить такую память, что часть ее должна быть выгружена, несколько из моих комментариев больше не имеют смысла.

17
ответ дан Aaron Digulla 7 November 2019 в 07:45
поделиться

Я работаю над SpiderMonkey, VM JavaScript, используемой в Firefox (и гном и немногие другие). Когда Вы вне памяти, можно хотеть сделать любую из следующих вещей:

  1. Выполнение сборщик мусора. Мы не выполняем сборщика мусора все время, когда это уничтожило бы производительность и батарею, поэтому к тому времени, когда Вы достигаете из ошибки памяти, немного мусора, возможно, накопилось.
  2. Свободная память. Например, избавьтесь от части кэша в оперативной памяти.
  3. Уничтожают или откладывают несущественные задачи. Например, разгрузите некоторые вкладки, которые не имеют использоваться в долгое время из памяти.
  4. вещи Журнала помочь разработчику диагностировать ошибку из памяти.
  5. Дисплей полухорошее сообщение об ошибке для уведомления пользователя, что продолжается.
  6. ...

Так да, существует много причин обработать ошибки из памяти вручную!

0
ответ дан 24 November 2019 в 12:03
поделиться

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

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

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

0
ответ дан 24 November 2019 в 12:03
поделиться

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

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

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

-1
ответ дан 24 November 2019 в 12:03
поделиться

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

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

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

0
ответ дан 24 November 2019 в 12:03
поделиться

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

0
ответ дан 24 November 2019 в 12:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: