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

Как перенаправить выход JVM без разрыва в выходе из приложения?

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

-XX:+PrintCompilation
-XX:+PrintGCDetails

и другие параметры для получения статуса JVM. Для контрольной информации я просто использую метод System.out.print(). Потому что мне нужно знать порядок сообщения, которое я распечатал, и выход JVM.

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

Когда мне нужно выполнить некоторые контрольные тесты, я бы хотел redirect the output into a file с помощью pipe (> in Linux system) и использовать python для получения результата из файла и анализа его.

Вот проблема:

The JVM output always overlapped with the messages I printed in the Java application. Это разрушило завершение сообщений.

Любая идея, как справиться с этой ситуацией? Мне нужно both the JVM output and application output in the same place in order to preserve the sequence because it is important. And they do not overlap on each other so I don't lose anything.

4b9b3361

Ответ 1

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

Вы можете прочитать больше на http://www.javabeat.net/2012/06/introduction-to-java-agents/ или http://today.java.net/pub/a/today/2008/04/24/add-logging-at-class-load-time-with-instrumentation.html

Ответ 2

Попробуйте использовать System.out.println() вместо System.out.print(). System.out.println() заставляет поток затухать внутри синхронизированной секции и, по крайней мере, ваш выход не будет таким смешанным.

Ответ 3

Использовать Log4J или управляемую сообщениями структуру ведения журнала в сравнении с System.out.println().

Log4J использует модель событий сообщения, которая гарантирует упорядочение сообщений. Кроме того, различные "приставки" могут использоваться для входа в базу данных или другой вывод/файл, что позволяет разделить пакет Java и другие атрибуты, чтобы данные не смешивались.

Кроме того, в этих строках рассмотрите использование высокопроизводительного таймера и/или не пытайтесь измерять очень короткие (миллисекундные) события. Причина в том, что вызов System.currentTimeMillis() будет в свою очередь вызывать часы операционной системы. На каждой ОС есть некоторый "дрейф часов" и кеширование, которое происходит так, что базовая системная функция может возвращать одно и то же значение, что приводит к смещениям +/- 30 мс в фактическое время. Чтобы исправить это или повысить точность, сгруппируйте измеряемые функции в достаточно большой размер выборки, а затем разделите их на количество итераций.

Например, выполните 10K операций, которые составляют 1-2 миллисекунды в качестве одной измеренной операции. Затем разделите на 10K, чтобы получить время за операцию.

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

Ответ 4

Непосредственная регистрация через System.out.print/println считается плохой практикой.

Почему?

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

В 2000 году был введен Log4J.
Он рассматривает все эти проблемы и с тех пор является более или менее стандартным решением. Несмотря на то, что есть некоторые новейшие и самые большие инструменты ведения журнала, которые пытаются выйти за пределы Log4J, вы все равно сможете получать мощные и гибкие результаты с помощью Log4J. Если вы переключите все вызовы System.out.print на Log4J, тогда ваша цитированная проблема и многие другие исчезнут.

http://logging.apache.org/log4j/1.2/manual.html

Ответ 5

Для -XX:+PrintCompilation вы можете использовать флаги -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation вместо этого, чтобы получить "подробный" вывод в отдельном файле "hotspot.log". Этот файл находится в формате XML и содержит информацию из -XX:+PrintCompilation и причину таких компиляций. Путь к файлу можно изменить с помощью -XX:LogFile=<new_hotspot_log>. Ссылка: https://wikis.oracle.com/display/HotSpotInternals/LogCompilation+overview

Для -XX:+PrintGCDetails вы можете использовать -Xloggc:<gc_log> для перенаправления вывода GC в указанный файл. Ссылка: java -X

Ответ 6

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

Сказав, что я уверен, что HS (в настоящее время Oracle) должен иметь возможность перенаправить вывод компилятора в файл. Вам просто нужно найти его достаточно сложно:-) У HS должна быть возможность распечатать все свои JVM и параметры компилятора, и среди них может быть тот, который перенаправляет вывод в файл.

В любом случае, я отвлекся...

1) В вашем $JAVA_HOME или% JAVA_HOME% должен быть src.zip. Он содержит исходный код библиотеки классов Java.

2) Измените System.out, чтобы перенаправить весь вывод на конкретный сбой или просто вставьте какой-то специальный символ, на котором вы могли бы grep захватить stdout и stderr. К сожалению, я не могу быть более конкретным с этим конкретным шагом, поскольку наша политика компании запрещает нам проверять содержимое src.zip. Я мог только представить, насколько трудным будет этот шаг. Возможно, это так же тривиально, как "выход" с вашим потоком вывода или так сложно, как изменение каждого метода печати, который ваше приложение использует напрямую. Я даже не знаю, сколько туземцев System.out использует

3) Поместите свою скомпилированную версию в файл jar.

4) Добавьте этот параметр в свою командную строку: -Xbootclasspath/p: full_path_to_your_jar. Это позволит JVM сначала использовать вашу версию класса. "P" означает прединд.

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

Ответ 7

Во-первых, я бы попробовал, что @barracel отметил об использовании System.out.println().

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

Ответ 8

Попробуйте разделить вывод JVM и вашего приложения.

  • Вывести информацию о JVM в stdout
  • Вывести информацию о вашем приложении в stderr с помощью "System.err.println()"
  • Проанализируйте результат с помощью ваших любимых инструментов.

Итак, командная строка выглядит так:

$java -XX:+PrintCompilation -XX:+PrintGCDetails MainClass 1>stdout.txt 2>stderr.txt

Ответ 9

Чтобы иметь выход с неперекрывающимся образом, используйте System.out.println. Тогда u можно перенаправить в тот же файл, как это:

java -XX:+PrintCompilation -XX:+PrintGCDetails MainClass 1>stdout.txt 2>&1

У этого есть вся ошибка, а также обычные выходы консоли в имени файла stdout.txt

Кроме того, если журналы имеют любую форму информации о потоке/времени, вы можете просто использовать

sort -n -k 1

где -k 1 обозначает столбец, в котором вы указали информацию о потоке/данных (эпохе).