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

Java Неверное имя файла дампа памяти кучи памяти

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

  • введите кучу дампа по-разному, основываясь на исходном процессе
  • удалить старые кучи для сохранения дискового пространства

При сбросе кучи на OOM с помощью

 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp

JVM создает файл со следующим именем java_pidXXXX.hprof в указанной папке /tmp (где XXXX является PID процесса). Нужно ли в любом случае указать другой формат, в котором PID и DATE используются для создания имени файла? После googling в течение часа я попробовал myPrefix_ $, {pid}, 'date' и т.д. Работающие только две вещи:

  • не указывать имя файла, и вы получаете java_pidXXXX.hprof
  • указать статическое имя файла, например. \TMP\OOM.hprof.

если папка \tmp не существует, она не создается и не создается куча дампа.

Единственная идея, которую можно использовать, - добавить команду в ошибку OOM

-XX:OnOutOfMemoryError="doSomething.sh %p"

но я пытался избежать этого, поскольку мне нужно развернуть "doSomething.sh"

4b9b3361

Ответ 1

-XX:HeapDumpPath в командной строке не дает вам больше гибкости, чем то, что вы уже обнаружили. То есть вы можете:

  • Задайте имя каталога, а затем в этом каталоге будет создано имя по умолчанию java_pidXXX.hprof.
  • Задайте имя файла, и этот файл будет использоваться как есть.

Соответствующий код в источнике HotSpot heapDumper.cpp. Читая его, он не ищет никаких "магических последовательностей" внутри данного пути:

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

Что это. Нет синтаксического анализа пути, не определяющего, является ли он каталогом или нет.

Единственная гибкость, которую вы можете добавить к ней, - использовать возможности оболочки при создании имени в командной строке. Вот почему вы можете увидеть несколько примеров в Интернете, которые используют что-то вроде name_`date`.ext - это обрабатывается оболочкой, которая заменяет `date` текущей датой один раз. То есть имя файла всегда будет иметь дату/время, когда оболочка обработала эту команду и запустила JVM, а не дату/время создания дампа. Если это будет достаточно для вас - вы можете это использовать. Обратите внимание, что в настоящее время считается более приемлемым использование синтаксиса name_$(date).ext.

Если вам нужна только дата, чтобы удалить старые файлы, вы можете удалить их в зависимости от времени последней модификации файла (утилита Unix/Linux find может вам помочь). Нет необходимости указывать дату в названии.

Тройка $(date) (или `date`) не помогает вам с PID. Оболочка также может заменить текущий PID, если вы используете $$, но это PID оболочки, которая обрабатывает командную строку, а не сам процесс JVM. Однако, если вы запускаете приложение JAVA с помощью команды shell exec, оно получает тот же идентификатор процесса, что и исходный код оболочки, поэтому вы можете использовать $$ для создания своего имени файла. Помните, что после exec ничего не будет выполнено из вашего script.

Итак, вы можете попробовать динамическое изменение имени файла, которое предложил @apangin в его ответе. Обратите внимание, однако, что, вероятно, будет немного сложно определить время самого дампа, так как вы хотите, чтобы имя файла было установлено до того, как произойдет OOM.

Ответ 2

HeapDumpPath - управляемая опция VM. Это означает, что вы можете установить его во все, что вы хотите во время выполнения, используя JMX.

    String pid = ManagementFactory.getRuntimeMXBean().getName();
    pid = pid.substring(0, pid.indexOf('@'));
    String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
    String fileName = "/tmp/heap_" + pid + "_" + date + ".dump";

    HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
            ManagementFactory.getPlatformMBeanServer(),
            "com.sun.management:type=HotSpotDiagnostic",
            HotSpotDiagnosticMXBean.class);
    bean.setVMOption("HeapDumpOnOutOfMemoryError", "true");
    bean.setVMOption("HeapDumpPath", fileName);