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




JNI. Фактически, с JNI сбой является режимом работы по умолчанию. Придется потрудиться, чтобы он не рухнул.
Возможно, разработчики JNI слышали о только аварийное программное обеспечение, но не совсем поняли идею.
Зависит от того, что вы подразумеваете под крахом.
Вы можете выполнить бесконечную рекурсию, чтобы исчерпать пространство стека, но это приведет к сбою "изящно". Вы получите исключение, но все будет обрабатывать сама JVM.
Вы также можете использовать JNI для вызова машинного кода. Если вы не сделаете это правильно, вы можете сильно разбить его. Отладка этих сбоев - это «весело» (поверьте мне, мне пришлось написать большую C++ DLL, которую мы вызываем из подписанного java-апплета). :)
Если вы измените этот бесконечный цикл for на рекурсивный вызов той же функции, вы получите исключение переполнения стека:
public static void main(String[] args) {
causeStackOverflow();
}
public void causeStackOverflow() {
causeStackOverflow();
}
Наиболее близким к единственному «ответу» является System.exit(), который немедленно завершает работу JVM без надлежащей очистки. Но кроме этого, наиболее вероятными ответами являются собственный код и исчерпание ресурсов. В качестве альтернативы вы можете поискать в системе отслеживания ошибок Sun ошибки в вашей версии JVM, некоторые из которых допускают повторяющиеся сценарии сбоев. Раньше мы получали полурегулярные сбои при приближении к пределу памяти в 4 ГБ в 32-битных версиях (сейчас мы обычно используем 64-битные).
без надлежащей очистки? уверены ли вы? В документации говорится: «Завершает работу текущей виртуальной машины Java, инициируя ее последовательность завершения работы ... все зарегистрированные обработчики завершения работы, если таковые имеются, запускаются ... все неактивированные финализаторы запускаются» - разве это не правильная очистка?
Это не сбой JVM, это целенаправленное и явное начало упорядоченного завершения работы.
Ближе к сбою jvm находится Runtime.getRuntime (). Halt (status). Согласно документам, «этот метод не вызывает запуск хуков выключения и не запускает неактивированные финализаторы, если финализация-при-выходе была включена». Все еще не сбой, но ближе, чем System.exit.
Это действительно плохой ответ.
Идеальная реализация JVM никогда не выйдет из строя.
Чтобы вывести из строя JVM, помимо JNI, вам нужно найти ошибку в самой виртуальной машине. Бесконечный цикл просто потребляет процессор. Бесконечное выделение памяти должно просто вызвать OutOfMemoryError в хорошо построенной JVM. Это, вероятно, вызовет проблемы для других потоков, но хорошая JVM все равно не должна давать сбой.
Если вы можете найти ошибку в исходном коде виртуальной машины и, например, вызвать ошибку сегментации при использовании памяти реализацией виртуальной машины, то вы действительно можете ее аварийно завершить.
В книге Джона Мейера Виртуальная машина Java есть пример серии инструкций байт-кода, которые вызвали дамп ядра JVM. Я не могу найти свой экземпляр этой книги. Если у кого-то есть, пожалуйста, найдите его и опубликуйте ответ.
Я бы не назвал выброс OutOfMemoryError или StackOverflowError сбоем. Это обычные исключения. Есть 3 способа действительно вывести виртуальную машину из строя:
Для последнего метода у меня есть небольшой пример, который спокойно приведет к сбою виртуальной машины Sun Hotspot:
public class Crash {
public static void main(String[] args) {
Object[] o = null;
while (true) {
o = new Object[] {o};
}
}
}
Это приводит к переполнению стека в GC, поэтому вы не получите StackOverflowError, а получите настоящий сбой, включая файл hs_err *.
Ух ты! Это приводит к сбою Sun Java 5, Sun Java 6 и OpenJDK 6 (в Ubuntu 9.04) без файла hs_err *, а только с ошибкой сегментации! ...
System.exit () - гораздо более простой способ вывести из строя JVM (если не установлен менеджер безопасности)
Не знаю, когда это было исправлено, просто протестировали в 1.7.0_09, и все в порядке. Получил ожидаемое: исключение в потоке «main» java.lang.OutOfMemoryError: пространство кучи Java в CrashJVM.main (CrashJVM.java:7)
Да, отлично работает в Java 7. Получено обычное исключение в потоке "main" java.lang.OutOfMemoryError: Java heap space
Я попробовал приведенный выше код на Intel Core i7 2,4 ГГц / 8 ГБ ОЗУ / JDK1.7 64bit, но JVM все еще работает через 20 минут. (Забавно: вентилятор моего ноутбука был громче, чем реактивный истребитель в небе). Исправлена ли эта проблема в JDK 1.7+?
В JDK 1.8_u71 это вызывает java.lang.OutOfMemoryError: GC overhead limit exceeded
Вы не можете знать, есть ли ошибки на всех виртуальных машинах.
Если вы определяете сбой как прерывание процесса из-за необработанной ситуации (т. Е. Отсутствия исключения или ошибки Java), это невозможно сделать изнутри Java (если у вас нет разрешения на использование класса sun.misc.Unsafe). В этом весь смысл управляемого кода.
Типичные сбои в машинном коде происходят из-за отмены ссылки указателей на неправильные области памяти (нулевой адрес или неправильно выровненный). Другим источником могут быть недопустимые машинные инструкции (коды операций) или необработанные сигналы из библиотек или вызовов ядра. Оба могут быть запущены, если в JVM или системных библиотеках есть ошибки.
Например, JIT-код (сгенерированный), собственные методы или системные вызовы (графический драйвер) могут иметь проблемы, приводящие к реальным сбоям (довольно часто возникал сбой, когда вы использовали функции ZIP, и им не хватало памяти). В этих случаях обработчик сбоя JVM срабатывает и сбрасывает состояние. Он также может сгенерировать файл ядра ОС («Доктор Ватсон» в Windows и дамп ядра в * nix).
В Linux / Unix вы можете легко вызвать сбой JVM, отправив сигнал запущенному процессу. Примечание: вы не должны использовать для этого SIGSEGV, поскольку Hotspot улавливает этот сигнал и в большинстве случаев повторно генерирует его как NullPointerException. Так что лучше прислать SIGBUS например.
на winxpsp2 w / wmp10 jre6.0_7
Desktop.open (uriToAviOrMpgFile)
Это приводит к тому, что порожденный поток бросает неперехваченный Throwable и приводит к сбою точки доступа.
YMMV
вот подробное объяснение того, что вызывает дамп ядра JVM (то есть сбой): http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534
Я делаю это сейчас, но не совсем уверен, как ... :-) JVM (и мое приложение) иногда просто полностью исчезают. Ошибок не выдается, ничего не регистрируется. Мгновенно без предупреждения переходит из режима работы в состояние отсутствия работы.
Начните проверять свое оборудование, особенно память!
К сожалению, он работает на нескольких машинах, которые в остальном работают нормально. Это делает только одно конкретное приложение (и оно не требует интенсивной работы с памятью или процессором).
Если вы хотите притвориться, что у вас закончилась память, вы можете сделать
public static void main(String[] args) {
throw new OutOfmemoryError();
}
Я знаю несколько способов вызвать дамп файла ошибки JVM, вызвав собственные методы (те, которые встроены), но, вероятно, лучше всего, если вы не знаете, как это сделать. ;)
JNI - большой источник сбоев. Вы также можете выйти из строя, используя интерфейс JVMTI, поскольку он также должен быть написан на C / C++.
Неисправное оборудование может привести к сбою любой программы. Однажды у меня случился воспроизводимый сбой приложения на одном компьютере, когда он работал нормально на других машинах с той же настройкой. Оказывается, у этой машины была неисправная оперативная память.
как обеспечить, чтобы ваш процесс попадал на один и тот же адрес страницы при каждом запуске? этот ответ похож на высказывание «если цунами обрушится на вашу деревню, ваш код обязательно выйдет из строя»
@ clockw0rk: если неисправная память находится в начале адресного пространства, и ваша программа использует много памяти, у вас есть очень хорошие шансы найти ее. Тем более, что обычно не работает должным образом не один байт.
Использовать это:
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:. Crash
РЕДАКТИРОВАТЬ: упрощенная версия с предложением напористого:
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
Вместо использования -Xbootclasspath вы также можете просто сделать это: Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null ); Отлично сработал для меня.
Unsafe по определению «небезопасен». Это немного обман.
Подтверждена работа с использованием трюка getDeclaredField в JDK 8u131 на Linux x64, включая производство hs_err_pid*.log из SIGSEGV.
Использование Unsafe не является читерством. OP не ищет «чистого» решения проблемы программирования. Ему нужно, чтобы jvm аварийно завершил работу самым уродливым образом. Это может случиться с помощью неприятных нативных вещей, и это именно то, что делает Unsafe.
Этот код приведет к сбою JVM неприятными способами
import sun.dc.pr.PathDasher;
public class Crash
{
public static void main(String[] args)
{
PathDasher dasher = new PathDasher(null) ;
}
}
Получение ошибки компиляции при использовании JDK 1.7 с этим кодом: Ограничение доступа: тип PathDasher недоступен из-за ограничения на требуемую библиотеку C: \ Program Files \ Java \ jdk1.7.0_51 \ jre \ lib \ rt.jar
Это бросает InternalError в JDK 1.8. JVM больше не дает сбоев.
Если вы хотите вывести JVM из строя - используйте следующее в Sun JDK 1.6_23 или ниже:
Double.parseDouble("2.2250738585072012e-308");
Это связано с ошибка в Sun JDK, который также присутствует в OpenJDK. Это исправлено начиная с Oracle JDK 1.6_24.
Я пришел сюда, потому что я также столкнулся с этим вопросом в Страстный программист, написанном Чадом Фаулером. Для тех, у кого нет доступа к копии, вопрос оформлен как своего рода фильтр / тест для кандидатов, проходящих собеседование на должность, требующую «действительно хороших программистов на Java».
В частности, он спрашивает:
How would you write a program, in pure Java, that would cause the Java Virtual Machine to crash?
Я программировал на Java более 15 лет и нашел этот вопрос одновременно и озадачивающим, и несправедливым. Как отмечали другие, Java, как управляемый язык, специально разработан не разбиться. Конечно, всегда есть ошибки JVM, но:
Как отмечали другие, некоторый собственный код через 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 или аналогичным исключением, которое, опять же, на самом деле не авария.
Так что же осталось? Я действительно хотел бы услышать, что автор действительно имел в виду как правильное решение.
Обновлять: Чад Фаулер ответил здесь.
PS: в остальном это отличная книга. Я поднял его для моральной поддержки во время изучения Ruby.
Такие вопросы на собеседовании служат лакмусовой бумажкой для разработчиков Java, которые существуют достаточно давно, чтобы 1) были свидетелями (многих) сбоев JVM и 2) сделали некоторые выводы или, что еще лучше, (самопровозглашенные) эксперты по Java попытались понять суть основные причины аварии. Чад Фаулер также утверждает в своей книге, что самопровозглашенные программисты на Java «даже не могли придумать неправильный ответ», т.е. не пытались думать о том, когда возникает целый класс потенциальных проблем. Итог: этот вопрос - это сегвей «Как предотвратить сбои JVM?» что, очевидно, даже лучше знать.
Я бы поискал людей, которые просто ответили (как и большинство здесь) «переполнение стека», system.exit () или другое «нормальное» завершение работы, поскольку они действительно не понимают JVM или слово «сбой». Признать (как и вы), что это очень ненормально, - довольно хороший способ определить более продвинутого программиста. Я согласен с вашим первым утверждением, я считаю, что это отличный и совершенно справедливый вопрос, который можно задать или задать - вопросы без конкретных ответов всегда будут лучшими.
опаздывает на вечеринку, но подход с использованием байт-кода звучит разумно: если вам удастся накормить с ложечки код vm JITTER, вы наверняка можете его разбить, возясь с регистрами или подобными вещами
кратчайший путь :)
public class Crash
{
public static void main(String[] args)
{
main(args);
}
}
Не вылетает. Это дает ошибку времени компиляции Exception in thread "main" java.lang.StackOverflowError at Test.main. Я использую jdk1.8.0_65
В прошлый раз, когда я пробовал это сделать:
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
Меня немного позабавило отрицательное голосование, учитывая, что это один из двух ответов, показывающих, как это сделать исключительно с помощью кода Java, и включает в себя полный код.
Я согласен с тем, что отрицательный голос неоправдан - это настоящий сбой, но как бы вы ответили на вопрос интервью? Если вы ранее не исследовали и не запомнили это, вы не могли бы дать его в качестве ответа на собеседовании, и если бы вы могли, я бы в любом случае счел нейтральный или плохой ответ - он не показывает, как вы подойдете к проблеме. Я ожидаю, что вы сделали Google для эксплойтов ошибок jvm и реализовали один, который является отличным ответом.
@BillK - Нет, это полностью моя собственная работа, хотя я придумал ее несколько лет назад, экспериментируя с разными вещами. В интервью я, скорее всего, сказал бы: «Я сделал это, используя try / catch и рекурсию, но сейчас я не могу назвать точный код».
Каковы подробности (версия JDK, любые аргументы виртуальной машины)? Не уверен, что это за версия "11.2-b0". Я использую это, но оно потребляет очень много ресурсов процессора.
@Hot Licks: Какова концепция в примере сбоя JVM? Почему JVM вылетает из-за кода. У всего потока есть отдельный поток стека ...
JVM аварийно завершает работу, потому что не ожидает этого сценария. Используется только один поток, поэтому подробности о потоках не имеют особого значения.
Разве это не просто вариант этот ответ, вызывающий переполнение стека в GC из-за глубоко связанных экземпляров Object[]? Я не уверен, добавляют ли рекурсия и finally что-нибудь к фактической причине сбоя ...
Если «Сбой» - это что-то, что прерывает нормальное завершение 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
}
Итак, это смотря какой тип АВАРИИ ?!
Создание исключения - это не сбой.
Однако необработанные исключения времени выполнения - это сбои, которыми является ArithmeticException.
Не сбой, но ближе к сбою, чем принятый ответ об использовании System.exit
Вы можете остановить JVM, позвонив
Runtime.getRuntime().halt( status )
Согласно документам: -
"this method does not cause shutdown hooks to be started and does not run uninvoked finalizers if finalization-on-exit has been enabled".
Самый короткий? Используйте класс Robot, чтобы вызвать CTRL + BREAK. Я заметил это, когда пытался закрыть свою программу, не закрывая консоль (у нее не было функции выхода).
Старый вопрос - надеюсь, кто-то извлечет выгоду из вашего ответа в будущем.
Мне нравится это <3, как насчет робота, который пишет в своем исходном коде, затем компилируется, запускается и завершает работу. назовем его "самоизменяющийся робот"
Если вы создаете процесс потока, который бесконечно порождает больше потоков (которые порождают больше потоков, которые ...), вы в конечном итоге вызовете ошибку переполнения стека в самой 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:
#
если бы вы сделали это с помощью процессов, в какой-то момент вы бы сломали компьютер. вы можете сделать это, используя runtime exec («файл .bat, который вызывает ваш JAR») -> jar открывает в своем конструкторе 2 новых runtime execs () -> аккуратная вилка-бомба, вставьте элемент Swing, и у вас есть классический хакер 90-х чувство лулза
Это считается?
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 с сообщением уничтожение текущего процесса не допускается.
Если под «крахом» вы подразумеваете резкое прерывание работы JVM, например, заставило бы JVM записывать в свой hs_err_pid% p.log, вы можете сделать это таким образом.
Установите для-Xmx arg крошечное значение и скажите JVM, что нужно вызвать сбой в outofmemory:
-Xmx10m -XX:+CrashOnOutOfMemoryError
Чтобы было ясно, без второго аргумента выше это просто приведет к jvm прекращение с OutOfMemoryError, но это не приведет к "сбою" или внезапному прерыванию jvm.
Этот метод оказался полезным, когда я пытался протестировать аргумент JVM -XX: ErrorFile, который определяет, где должен быть записан такой журнал hs_err_pid. Я нашел этот пост здесь, пытаясь найти способы вызвать такой сбой. Когда позже я обнаружил, что вышеперечисленное работает как самый простой для меня, я хотел добавить его в список здесь.
Наконец, FWIW, если кто-то может проверить это, когда у них уже есть значение -Xms, установленное в ваших аргументах (на какое-то большее значение, чем указано выше), вы захотите удалить или изменить это также, иначе вы получите не сбой, а просто сбой запуска jvm с сообщением «Начальный размер кучи установлен на большее значение, чем максимальный размер кучи». (Это было бы не очевидно, если бы JVM запускалась как служба, например, с некоторыми серверами приложений. Опять же, это укусило меня, поэтому я хотел поделиться им.)
он работает для тестирования JVM -XX: ErrorFile arg @Charlie
Я не могу сказать: Сэнди, ваш комментарий просто добавляет подтверждение тому, что я сказал, как «этот метод оказался полезным, когда я пытался протестировать аргумент JVM -XX: ErrorFile»? Если да, то спасибо. Если вы, возможно, думали, что я сомневаюсь в том, что это «сработает» для проверки этого, я не был. :-)
Возникла эта проблема при попытке реплицировать сбой JVM.
Jni работает, но его нужно настроить для разных платформ. В конце концов, я использую эту комбинацию для сбоя JVM
-XX:+CrashOnOutOfMemoryErrorlong[] l = new long[Integer.MAX_VALUE]; для запуска OOMТогда JVM выйдет из строя и создаст журнал сбоев.
Возможный расширенный набор: stackoverflow.com/questions/6470651/…