Как вы разбиваете JVM?

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

У кого-нибудь есть идея?

Ответ 1

Наиболее близким к единственному "ответу" является System.exit() который немедленно завершает работу JVM без надлежащей очистки. Но кроме этого, нативный код и исчерпание ресурсов являются наиболее вероятными ответами. В качестве альтернативы вы можете посмотреть на багтрекер Sun на наличие ошибок в вашей версии JVM, некоторые из которых допускают повторяющиеся сценарии сбоев. Мы привыкли получать полурегулярные сбои при приближении к пределу памяти 4 Гб в 32-битных версиях (сейчас мы обычно используем 64-битные).

Ответ 2

Я бы не назвал выкидывание ошибки OutOfMemoryError или StackOverflowError. Это просто нормальные исключения. Чтобы действительно свернуть виртуальную машину, есть 3 способа:

  • Используйте JNI и сбой в собственном коде.
  • Если менеджер безопасности не установлен, вы можете использовать отражение для сбоя виртуальной машины. Это специфично для VM, но обычно VM хранит кучу указателей на собственные ресурсы в частных полях (например, указатель на собственный объект потока хранится в длинном поле в java.lang.Thread). Просто измените их с помощью отражения, и VM рано или поздно рухнет.
  • Все виртуальные машины имеют ошибки, поэтому вам просто нужно вызвать один из них.

Для последнего метода у меня есть краткий пример, который очень быстро отключит виртуальную виртуальную машину Sun Hotspot:

public class Crash {
    public static void main(String[] args) {
        Object[] o = null;

        while (true) {
            o = new Object[] {o};
        }
    }
}

Это приводит к переполнению стека в GC, поэтому вы не получите StackOverflowError, а реальный сбой, включая файл hs_err *.

Ответ 3

JNI. Фактически, с JNI сбой - это режим работы по умолчанию. Вы должны усердно работать, чтобы он не разбился.

Ответ 4

Используйте это:

import sun.misc.Unsafe;

public class Crash {
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    public static void crash() {
        unsafe.putAddress(0, 0);
    }
    public static void main(String[] args) {
        crash();
    }
}

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

java -Xbootclasspath/p:. Крушение

Ответ 5

Я пришел сюда, потому что я также столкнулся с этим вопросом в "Страстном программисте " Чеда Фаулера. Для тех, у кого нет доступа к копии, вопрос оформлен как своего рода фильтр/тест для кандидатов, проходящих собеседование на должность, требующую "действительно хороших Java-программистов".

В частности, он спрашивает:

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

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

  1. После 15+ лет производства JRE, это редкость.
  2. Любые такие ошибки, вероятно, будут исправлены в следующем выпуске, так какова вероятность того, что вы, как программист, столкнетесь и вспомните детали текущего набора JRE show-stoppers?

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

Другим вариантом может быть подача фиктивных байтовых кодов JRE; достаточно просто выгрузить некоторые двоичные данные мусора в файл .class и попросить JRE запустить его:

$ echo 'crap crap crap' > crap.class
$ java crap
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file crap

Это считается? Я имею в виду, что сама JRE не разбилась; он правильно обнаружил поддельный код, сообщил об этом и вышел.

Это оставляет нас с наиболее очевидными видами решений, такими как очистка стека с помощью рекурсии, RuntimeException памяти кучи с помощью выделения объектов или просто RuntimeException. Но это просто приводит к завершению работы JRE со StackOverflowError или аналогичным исключением, что опять-таки не является крахом.

Так что же осталось? Мне бы очень хотелось услышать, что автор действительно имел в виду как правильное решение.

Обновление: Чед Фаулер ответил здесь.

PS: это отличная книга. Я взял это для моральной поддержки, изучая Руби.

Ответ 6

Этот код приведет к сбою JVM неприятными способами

import sun.dc.pr.PathDasher; 

public class Crash
{
     public static void main(String[] args)
     {    
        PathDasher dasher = new PathDasher(null) ;
     }
}

Ответ 7

В прошлый раз я попытался это сделать:

public class Recur {
    public static void main(String[] argv) {
        try {
            recur();
        }
        catch (Error e) {
            System.out.println(e.toString());
        }
        System.out.println("Ended normally");
    }
    static void recur() {
        Object[] o = null;
        try {
            while(true) {
                Object[] newO = new Object[1];
                newO[0] = o;
                o = newO;
            }
        }
        finally {
            recur();
        }
    }
}

Первая часть сгенерированного файла журнала:

#
# An unexpected error has been detected by Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x000000006dad5c3d, pid=6752, tid=1996
#
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.2-b01 mixed mode windows-amd64)
# Problematic frame:
# V  [jvm.dll+0x2e5c3d]
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x00000000014c6000):  VMThread [stack: 0x0000000049810000,0x0000000049910000] [id=1996]

siginfo: ExceptionCode=0xc00000fd, ExceptionInformation=0x0000000000000001 0x0000000049813fe8 

Registers:
EAX=0x000000006dc83090, EBX=0x000000003680f400, ECX=0x0000000005d40ce8, EDX=0x000000003680f400
ESP=0x0000000049813ff0, EBP=0x00000000013f2df0, ESI=0x00000000013f0e40, EDI=0x000000003680f400
EIP=0x000000006dad5c3d, EFLAGS=0x0000000000010206

Ответ 8

Идеальная реализация JVM никогда не сбой.

Чтобы сбой JVM, помимо JNI, вам нужно найти ошибку в самой виртуальной машине. Бесконечный цикл просто потребляет процессор. Бесконечно распределяющая память должна просто вызывать OutOfMemoryError в хорошо построенной JVM. Это, вероятно, вызовет проблемы для других потоков, но хорошая JVM по-прежнему не должна аварийно завершаться.

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

Ответ 9

Если вы хотите завершить работу JVM - используйте следующее в Sun JDK 1.6_23 или ниже:

Double.parseDouble("2.2250738585072012e-308");

Это связано с ошибкой в Sun JDK, также обнаруженной в OpenJDK. Это исправлено в Oracle JDK 1.6_24 и далее.

Ответ 10

Зависит от того, что вы имеете в виду при аварии.

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

Вы также можете использовать JNI для вызова собственного кода. Если вы не сделаете это прямо сейчас, вы можете заставить его крушить. Отладка этих сбоев "весело" (поверьте мне, мне пришлось написать большую С++ DLL, которую мы вызываем из подписанного java-апплета).:)

Ответ 11

В книге Java Virtual Machine от Джона Мейера приведен пример последовательности инструкций байткода, которые вызвали JVM к дампу ядра. Я не могу найти свою копию этой книги. Если кто-нибудь там есть, пожалуйста, просмотрите его и отправьте ответ.

Ответ 12

на winxpsp2 w/wmp10 jre6.0_7

Desktop.open(uriToAviOrMpgFile)

Это приводит к тому, что порожденный поток бросает невидимую Throwable и сбрасывает горячую точку

YMMV

Ответ 13

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

Ответ 14

кратчайший возможный способ:)

public class Crash
{
    public static void main(String[] args)
    {
        main(args);
    }
}

Ответ 15

Не сбой, но ближе к сбою, чем принятый ответ на использование System.exit

Вы можете остановить JVM, вызвав

Runtime.getRuntime().halt( status )

Согласно документам: -

"этот метод не вызывает запуск завершающих зацепок и не запускает неинвинированные финализаторы, если включена опция finalization-on-exit".

Ответ 16

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

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

Например, JITed (сгенерированный) код, встроенные методы или системные вызовы (графический драйвер) могут иметь проблемы, приводящие к реальным сбоям (довольно часто возникали сбои при использовании ZIP-функций, и у них не хватало памяти). В этих случаях обработчик сбоев JVM запускает и сбрасывает состояние. Он также может генерировать основной файл ОС (Dr. Watson для Windows и core dump on * nix).

В Linux/Unix вы можете легко сделать JVM-крах, отправив ему сигнал в текущий процесс. Примечание: вы не должны использовать SIGSEGV для этого, поскольку Hotspot ловит этот сигнал и повторно бросает его как исключение NullPointerException в большинстве мест. Поэтому лучше отправить SIGBUS например.

Ответ 18

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

public static void main(String[] args) {
    throw new OutOfmemoryError();
}

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

Ответ 19

JNI - большой источник сбоев. Вы также можете сбой с использованием интерфейса JVMTI, так как это также должно быть написано на C/С++.

Ответ 20

Если вы создаете процесс потока, который бесконечно порождает больше потоков (которые порождают больше потоков, которые...), вы в конечном итоге вызовете ошибку в самой JVM.

public class Crash {
    public static void main(String[] args) {

        Runnable[] arr = new Runnable[1];
        arr[0] = () -> {

            while (true) {
                new Thread(arr[0]).start();
            }
        };

        arr[0].run();
    }
}

Это дало мне результат (через 5 минут, посмотри свой баран)

An unrecoverable Qaru has occurred.
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x0000000070e53ed7, pid=12840, tid=0x0000000000101078
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# 

Ответ 21

Кратчайший? Используйте класс Robot для запуска CTRL + BREAK. Я заметил это, когда пытался закрыть свою программу, не закрывая консоль (у нее не было функциональности "выхода" ).

Ответ 22

Если вы измените этот бесконечный цикл на рекурсивный вызов той же функции, вы получите исключение:

public static void main(String[] args) {
    causeStackOverflow();
}

public void causeStackOverflow() {
    causeStackOverflow();
}

Ответ 23

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

Ответ 24

Это считается?

long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}

Работает только для Linux и Java 9.

По какой-то причине я не понимаю, ProcessHandle.current().destroyForcibly(); не уничтожает JVM и создает исключение java.lang.IllegalStateException с сообщением об удалении текущего процесса, которое не разрешено.

Ответ 25

Если под "аварийным завершением" вы имеете в виду внезапное прерывание работы JVM, такое, как если бы JVM выполнило запись в его hs_err_pid% p.log, вы можете сделать это следующим образом.

Установите для аргумента -Xmx значение крошечное и скажите JVM вызвать сбой вне памяти:

 -Xmx10m -XX:+CrashOnOutOfMemoryError

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

Этот метод оказался полезным, когда я пытался протестировать JVM -XX: ErrorFile arg, который определяет, где должен быть записан такой журнал hs_err_pid. Я нашел этот пост здесь, пытаясь найти способы вызвать такой крах. Позже я обнаружил, что вышеперечисленное работает как самый простой для моих нужд, я хотел добавить его в список здесь.

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

Ответ 26

Если "Crash" - это что-то, что прерывает jvm/program от обычного завершения, то исключение Un-Handled может сделать это.

public static void main(String args[]){
   int i = 1/0;
   System.out.print(i); // This part will not be executed due to above  unhandled exception
  }

Итак, это зависит от того, какой тип CRASH?!