Подтвердить что ты не робот

Обнаружение ошибок в памяти

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

Наивный подход для этого заключался в том, чтобы установить неперехваченный обработчик исключений для каждого потока и проверить, является ли возбужденное исключение экземпляром OutOfMemoryError и установить соответствующий флаг. Однако этот подход нереалистичен по следующим причинам:

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

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

У нас включен -XX:+HeapDumpOnOutOfMemoryError, но я не рассматриваю это как решение этой проблемы, поскольку он был разработан для чего-то другого - и при этом он не выполняет обратного вызова Java, когда это происходит.

Кто-нибудь это сделал? Как бы вы решили его или предложили его решить? Любые идеи приветствуются.

4b9b3361

Ответ 1

Вы можете использовать систему предупреждения из памяти; это http://www.javaspecialists.eu/archive/Issue092.html может быть вдохновением. Вы можете настроить прослушиватель, который вызывается после того, как определенный порог памяти (скажем, 80%) нарушен - вы можете использовать этот вызов, чтобы начать принимать корректирующие меры.

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

Ответ 2

Существует статья на основе сообщения, которое Скорпион уже дал ссылку.

Метод снова основан на использовании MemoryPoolMXBean и подписывается на событие с превышением порога памяти, но немного отличается от того, что было описано в оригинальной записи.

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

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

Ответ 3

У нас есть -XX: + HeapDumpOnOutOfMemoryError включен, но я не вижу этого как решение этой проблемы, поскольку оно предназначено для чего-то другого - и при этом не происходит обратного вызова Java.

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

Инструмент для байткода возможен - но жесткий. Инструмент мониторинга HPjmeter имеет возможность прогнозировать будущий OOM (с оговорками), но только на системах на базе HP-UX/Itanium. Вы можете выделить поток демона для вычисления используемой памяти в процессе и вызвать предупреждение, когда это будет превышено, но на самом деле вы не решаете проблему.

Ответ 4

Вы можете поймать все и все неперехваченные исключения со статическим Thread.setDefaultUncaughtExceptionHandler. Конечно, это не помогает, если кто-то ловит все Throwables. (Я не думаю, что что-то будет, хотя с OOME я бы заподозрил, что вы получите эффект каскадирования, пока что-то вне злостного блока try не взорвется.) Надеюсь, поток выпустил бы достаточно памяти для обработчика исключений Работа; Ошибки OOM имеют тенденцию к умножению, когда вы пытаетесь с ними справиться.