저자가 인터뷰 대상자에게 "JVM을 어떻게 충돌 시키는가?"라는 프로그래밍 기술에 관한 책을 읽고있었습니다. 결국 모든 메모리를 사용하는 무한 for-loop를 작성하여 그렇게 할 수 있다고 생각했습니다.
누구든지 어떤 아이디어가 있습니까?
저자가 인터뷰 대상자에게 "JVM을 어떻게 충돌 시키는가?"라는 프로그래밍 기술에 관한 책을 읽고있었습니다. 결국 모든 메모리를 사용하는 무한 for-loop를 작성하여 그렇게 할 수 있다고 생각했습니다.
누구든지 어떤 아이디어가 있습니까?
답변:
단일 "응답"에 가장 가까운 것은 System.exit()
적절한 정리없이 즉시 JVM을 종료하는 것입니다. 그러나 그 외에도 네이티브 코드와 리소스 소모가 가장 가능성이 높은 답변입니다. 또는 JVM 버전에서 버그를 Sun의 버그 추적기에서 찾아 볼 수 있습니다.이 중 일부는 반복 가능한 충돌 시나리오를 허용합니다. 우리는 32 비트 버전에서 4Gb 메모리 제한에 접근 할 때 반 정기 충돌을 겪었습니다 (일반적으로 64 비트를 사용합니다).
OutOfMemoryError 또는 StackOverflowError에 충돌을 발생시키는 호출을하지 않습니다. 이것들은 단지 일반적인 예외입니다. VM을 실제로 크래시하려면 다음 세 가지 방법이 있습니다.
마지막 방법으로 간단한 예를 들었습니다. Sun 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
생산을 포함하여, 리눅스 64에서 JDK 8u131에 트릭을 hs_err_pid*.log
A로부터 SIGSEGV
.
Unsafe
은 속임수가 아닙니다. OP는 프로그래밍 문제에 대한 '깨끗한'솔루션을 찾고 있지 않습니다. 그는 가장 추악한 방법으로 jvm이 충돌해야합니다. 불쾌한 네이티브 일을하는 것이 그 일을 할 수있는 일이며, 정확히 그렇습니다 Unsafe
.
Chad Fowler의 The Passionate Programmer 에서도이 질문에 부딪 쳤기 때문에 여기에 왔습니다 . 사본에 접근 할 수없는 사람들을 위해, 질문은 "정말로 훌륭한 자바 프로그래머"가 필요한 입장을 인터뷰하는 응시자들을위한 일종의 필터 / 테스트로 구성됩니다.
특히 그는 묻습니다.
순수 Java로 Java Virtual Machine이 충돌하는 프로그램을 어떻게 작성 하시겠습니까?
저는 15 년 이상 Java로 프로그래밍했으며이 질문은 당혹스럽고 불공평 한 것으로 나타났습니다. 다른 사람들이 지적했듯이 관리되는 언어 인 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
비슷한 예외 로 종료되어 실제로 충돌이 아닙니다 .
남은 것은 무엇입니까? 저자가 실제로 올바른 솔루션으로 생각한 것을 듣고 싶습니다.
업데이트 : Chad Fowler 가 여기에 응답했습니다 .
추신 : 그것은 다른 위대한 책입니다. 루비를 배우면서 도덕적 지원을 받기 위해 그것을 선택했습니다.
이 코드는 불쾌한 방식으로 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을 중단하려면 Sun JDK 1.6_23 이하에서 다음을 사용하십시오.
Double.parseDouble("2.2250738585072012e-308");
이것은 Sun JDK 의 버그 때문 입니다. OpenJDK에서도 발견되었습니다. 이것은 Oracle JDK 1.6_24부터 수정되었습니다.
Jon Meyer의 Java Virtual Machine 이라는 책 에는 JVM이 코어 덤프되도록하는 일련의 바이트 코드 명령에 대한 예가 있습니다. 이 책의 사본을 찾을 수 없습니다. 누군가가 있다면 그것을 찾아 답을 게시하십시오.
winxpsp2에서 wmp10으로 jre6.0_7
Desktop.open (uriToAviOrMpgFile)
이로 인해 스폰 된 스레드가 catch되지 않은 Throwable을 발생시키고 핫스팟이 충돌합니다.
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를 사용하고 있습니다
다음은 JVM이 코어 덤프를 일으키는 원인 (예 : 충돌)에 대한 자세한 설명입니다. http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534
처리되지 않은 상황 (예 : Java 예외 또는 오류 없음)으로 인해 충돌을 프로세스 중단으로 정의한 경우 (sun.misc.Unsafe 클래스를 사용할 권한이없는 경우) Java 내에서이를 수행 할 수 없습니다. 이것이 관리 코드의 요점입니다.
네이티브 코드의 일반적인 충돌은 잘못된 메모리 영역 (널 주소 또는 정렬 오류)에 대한 포인터를 역 참조함으로써 발생합니다. 다른 소스는 잘못된 기계 명령어 (opcode)이거나 라이브러리 또는 커널 호출에서 처리되지 않은 신호일 수 있습니다. JVM 또는 시스템 라이브러리에 버그가있는 경우 둘 다 트리거 될 수 있습니다.
예를 들어 JITed (생성 된) 코드, 기본 메소드 또는 시스템 호출 (그래픽 드라이버)은 실제 충돌로 이어질 수 있습니다 (ZIP 함수를 사용하고 메모리가 부족할 때 충돌이 발생하는 것이 일반적 임). 이러한 경우 JVM의 크래시 핸들러가 시작되어 상태를 덤프합니다. 또한 OS 코어 파일 (Windows의 Dr. Watson 및 * nix의 코어 덤프)을 생성 할 수 있습니다.
Linux / Unix에서는 실행중인 프로세스에 신호를 보내 JVM 충돌을 쉽게 일으킬 수 있습니다. 참고 : SIGSEGV
핫스팟은이 신호를 잡아서 대부분의 장소에서 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이 hs_err_pid % p.log에 쓰이게하는 등 갑자기 중단되는 JVM을 의미하는 경우이 방법으로 수행 할 수 있습니다.
-Xmx arg를 작은 값으로 설정하고 메모리 부족으로 인해 충돌이 발생하도록 JVM에 지시하십시오.
-Xmx10m -XX:+CrashOnOutOfMemoryError
분명히 위의 두 번째 인수가 없으면 jvm 이 OutOfMemoryError로 종료 되지만 jvm 이 "충돌"되거나 갑자기 중단되지는 않습니다.
이 기술은 JVM -XX : ErrorFile arg를 테스트 할 때 도움이되었으며, 이러한 hs_err_pid 로그를 작성해야하는 위치를 제어합니다. 그런 충돌을 일으키는 방법을 찾으려고 하면서이 게시물을 찾았습니다. 나중에 위의 내용이 내 필요에 가장 쉬운 것으로 밝혀지면 여기에 목록에 추가하고 싶었습니다.
마지막으로, FWIW, 누군가가 이미 args에 -Xms 값을 설정했을 때 이것을 테스트 할 수 있다면 (위보다 더 큰 값으로), 제거하거나 변경하고 싶거나 충돌하지 않고 단순히 "초기 힙 크기가 최대 힙 크기보다 큰 값으로 설정 됨"을보고하는 jvm 시작 실패 (일부 응용 프로그램 서버와 같은 서비스로 JVM을 실행하는 경우 분명하지 않습니다. 다시 한 번 말하지만 공유하고 싶었습니다.)
나는 지금하고 있지만, 어떻게 ... :-) 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
의 메시지 destroy not allowed 메시지를 던집니다 .
'충돌'이 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
}
따라서 어떤 유형의 CRASH에 달려 있습니까?!
ArithmeticException
입니다