Я читав книгу про навички програмування, в якій автор запитував респондента: "Як ви розбиваєте JVM?" Я думав, що ви можете це зробити, написавши нескінченний цикл for, який врешті-решт використає всю пам'ять.
Хтось має ідею?
Я читав книгу про навички програмування, в якій автор запитував респондента: "Як ви розбиваєте JVM?" Я думав, що ви можете це зробити, написавши нескінченний цикл for, який врешті-решт використає всю пам'ять.
Хтось має ідею?
Відповіді:
Найближче до однієї "відповіді" - це те, System.exit()
що припиняється JVM негайно без належної очистки. Але крім цього, найвірогідніші відповіді - рідний код та виснаження ресурсів. Крім того, ви можете переглянути трекер помилок Sun щодо помилок у вашій версії JVM, деякі з яких дозволяють повторювати сценарії аварій. Ми отримували напіврегулярні збої, коли підходили до ліміту пам'яті 4 Гб у 32-бітних версіях (зараз ми зазвичай використовуємо 64-бітні).
Я б не називав викид OutOfMemoryError або StackOverflowError аварією. Це лише звичайні винятки. Для справжнього виходу з ладу VM є 3 способи:
Для останнього методу я маю короткий приклад, який невдало зірве VM Hotspot VM:
public class Crash {
public static void main(String[] args) {
Object[] o = null;
while (true) {
o = new Object[] {o};
}
}
}
Це призводить до переповнення стека в GC, тому ви не отримаєте StackOverflowError, а справжній збій, включаючи файл hs_err *.
java.lang.OutOfMemoryError: GC overhead limit exceeded
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:. Збій
Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null );
для мене добре працювали.
Unsafe
є, за визначенням, "небезпечним". Це трохи обман.
getDeclaredField
трюку в JDK 8u131 на Linux x64, включаючи виробництво hs_err_pid*.log
з a SIGSEGV
.
Unsafe
- це не обман. ОП не шукає «чистого» рішення проблеми програмування. Йому потрібен jvm, щоб збитися якомога потворнішим способом. Робити неприємні рідні речі - це те, що може зробити це, і саме це і Unsafe
робиться.
Я прийшов сюди, тому що я також зіткнувся з цим питанням у Страсному програмісті Чада Фаулера. Для тих, хто не має доступу до копії, питання формулюється як своєрідний фільтр / тест для кандидатів, які беруть інтерв'ю на посаду, яка вимагає "дійсно хороших програмістів Java".
Зокрема, він запитує:
Як би ви написали програму на чистому Java, яка спричинила б збій віртуальної машини 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: це інакше чудова книга. Я підібрав це для моральної підтримки під час навчання Рубі.
Цей код розбиває JVM неприємними способами
import sun.dc.pr.PathDasher;
public class Crash
{
public static void main(String[] args)
{
PathDasher dasher = new PathDasher(null) ;
}
}
InternalError
в JDK 1.8. JVM більше не виходить з ладу.
Востаннє я намагався це зробити:
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 все одно не повинен виходити з ладу.
Якщо ви можете знайти помилку у вихідному коді VM і, наприклад, викликати помилку сегментації у використанні пам'яті реалізації VM, то ви можете насправді її зламати.
Якщо ви хочете зірвати 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 w / wmp10 jre6.0_7
Desktop.open (uriToAviOrMpgFile)
Це призводить до того, що породжена нитка викине невловимий метальний і вибиває точку доступу
YMMV
Зламана апаратура може вивести з ладу будь-яку програму. У мене колись сталася аварійна аварія на певній машині, коли вона працювала на інших машинах із точно такою ж настройкою. Виявляється, що машина мала несправну оперативну пам’ять.
найкоротший можливий шлях :)
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
Не збій, а ближче до аварії, ніж прийнята відповідь використання System.exit
Ви можете зупинити JVM, зателефонувавши
Runtime.getRuntime().halt( status )
За даними:
"цей метод не спричиняє запуск гачок відключення та не запускає незвані фіналізатори, якщо фіналізація при виході була включена".
ось детальне пояснення того, що спричиняє JVM до основного дампа (тобто збій): http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534
Якщо ви хочете зробити вигляд, що у вас закінчилося пам'ять, ви можете це зробити
public static void main(String[] args) {
throw new OutOfmemoryError();
}
Я знаю пару способів викликати скидання файлу помилок JVM шляхом виклику власних методів (вбудованих), але, мабуть, найкраще ви не знаєте, як це зробити. ;)
Якщо ви визначите збій як переривання процесу через нездійснену ситуацію (тобто відсутність виключення Java або помилка), це неможливо зробити зсередини Java (якщо ви не маєте дозволу на використання класу sun.misc.Unsafe). У цьому вся суть керованого коду.
Типові збої в нативному коді трапляються шляхом відсилання вказівників на неправильні області пам’яті (нульова адреса або неправильне налаштування). Іншим джерелом можуть бути незаконні інструкції на машині (опкоди) або необроблені сигнали з викликів бібліотеки або ядра. І те й інше може бути спрацьовано, якщо JVM або системні бібліотеки мають помилки.
Наприклад, код JITed (згенерований), нативні методи або системні виклики (графічний драйвер) можуть мати проблеми, що призводять до реальних збоїв (досить часто трапляються збої, коли ви використовуєте ZIP-функції, і у них не вистачає пам'яті). У цих випадках обробник аварій JVM запускає та скидає державу. Він також може генерувати основний файл ОС (Dr. Watson для Windows та основний дамп на * nix).
У Linux / Unix ви можете легко зробити збій JVM, відправивши його сигнал до запущеного процесу. Примітка: не слід використовувати SIGSEGV
для цього, оскільки Hotspot ловить цей сигнал і повторно передає його як NullPointerException у більшості місць. Тож краще надіслати SIGBUS
приклад.
Якщо ви створите процес потоку, який нескінченно породжує більше потоків (які породжують більше ниток, які ...), врешті ви викликаєте помилку переповнення стека в самому 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:
#
Якщо під «крахом» ви маєте на увазі різкий перерив JVM, такий як, що призведе до того, що JVM запише його hs_err_pid% p.log , ви можете зробити це таким чином.
Встановіть аргумент-Xmx на крихітне значення та скажіть JVM, щоб примусити збій на outfememory:
-Xmx10m -XX:+CrashOnOutOfMemoryError
Щоб було зрозуміло, без другого аргументу вище, це просто призведе до того, що jvm закінчиться OutOfMemoryError, але він не "збоїться" або різко скасує jvm.
Ця методика виявилася корисною, коли я намагався протестувати аргумент JVM -XX: ErrorFile, який контролює, де такий запис hs_err_pid повинен бути записаний. Я знайшов цю посаду тут, намагаючись знайти способи змусити такий збій. Коли згодом я виявив, що вищезазначене працювало як найлегше для моєї потреби, я хотів додати його до списку тут.
Нарешті, FWIW, якщо хтось може перевірити це, коли у них вже встановлено значення -Xms у ваших аргументах (на якесь більше значення, ніж вище), ви також захочете видалити або змінити це, інакше ви отримаєте не збій, а просто невдача запуску jvm, повідомляючи про "Початковий розмір купи, встановлений на велике значення, ніж максимальний розмір купи". (Це не було б очевидно, якби запустити JVM як службу, наприклад, із деякими серверами додатків. Знову ж таки, це мене покусало, тому я хотів ним поділитися.)
Якщо ви зміните цей нескінченний цикл на рекурсивний виклик тієї самої функції, ви отримаєте виняток переповнення стека:
public static void main(String[] args) {
causeStackOverflow();
}
public void causeStackOverflow() {
causeStackOverflow();
}
Я роблю це зараз, але не зовсім впевнений, як ... :-) JVM (і мій додаток) іноді просто повністю зникають. Жодних помилок не викинуто, нічого не зареєстровано. Переходить від роботи до того, щоб зовсім не працювати без миттєвого попередження.
Найкоротший? Використовуйте клас роботів, щоб запустити CTRL + BREAK. Я помітив це, коли я намагався закрити свою програму, не закриваючи консоль (у неї не було функцій "виходу").
Чи враховується це?
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.
Jni працює, але його потрібно налаштувати для різних платформ. Врешті-решт, я використовую цю комбінацію, щоб зробити аварію JVM
-XX:+CrashOnOutOfMemoryError
long[] l = new long[Integer.MAX_VALUE];
щоб запустити OOMТоді JVM вийде з ладу і генерує журнал аварій.
Якщо "Збій" - це щось, що перериває jvm / програму від нормального завершення, то це може зробити виняток 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
}
Отже, це залежить від того, який тип КРАНУ ?!
ArithmeticException
це