Вопрос

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

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

Это было полезно?

Решение

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

Другие советы

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

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

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

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

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

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

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

Использовать это:

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:.Крушение

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

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

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

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

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

Как уже отмечали другие, некоторый собственный код через 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.Но это просто приводит к завершению работы JRE с StackOverflowError или подобное исключение, которое опять же это не совсем авария.

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

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

ПС:в остальном это отличная книга.Я взял его для моральной поддержки при изучении Ruby.

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

import sun.dc.pr.PathDasher; 

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

В прошлый раз, когда я попробовал это, это сделало бы это:

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

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

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

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

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

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

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

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

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

Вы также можете использовать JNI для вызова собственного кода.Если вы не сделаете это правильно, вы можете усугубить ситуацию.Отладка этих сбоев — это «забавно» (поверьте мне, мне пришлось написать большую C++ DLL, которую мы вызываем из подписанного Java-апплета).:)

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

на winxpsp2 с wmp10 jre6.0_7

Desktop.open(uriToAviOrMpgFile)

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

ЯММВ

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

самый короткий путь :)

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

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

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

Runtime.getRuntime().halt( status )

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

«Этот метод не вызывает запуск перехватчиков завершения работы и не запускает невызванные финализаторы, если включена финализация при выходе».

вот подробное объяснение того, что вызывает дамп ядра JVM (т.е.крушение):http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534

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

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

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

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

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

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

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

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

Если вы создадите потоковый процесс, который бесконечно порождает больше потоков (которые порождают больше потоков, что...), вы в конечном итоге вызовете ошибку переполнения стека в самой 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 stack overflow 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:
# 

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

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

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

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 с сообщением уничтожение текущего процесса не разрешено.

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

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

public void causeStackOverflow() {
    causeStackOverflow();
}

Если «Сбой» — это что-то, что прерывает нормальное завершение работы jvm/программы, то это может сделать необработанное исключение.

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
  }

Так это смотря какого типа АВАРИЯ?!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top