IT이야기

JVM을 크래시하려면 어떻게 해야 합니까?

cyworld 2022. 7. 25. 22:45
반응형

JVM을 크래시하려면 어떻게 해야 합니까?

필자가 인터뷰 대상자에게 JVM을 크래시하는 방법을 묻는 프로그래밍 기술에 관한 책을 읽다가 결국 메모리를 다 써버리는 무한 for-loop을 쓰면 될 것 같다는 생각이 들었다.

누구 짐작 가는 사람?

Out Of Memory Error 또는 Stack Overflow Error를 던지는 것은 크래시라고 할 수 없습니다.이것들은 일반적인 예외입니다.VM을 실제로 크래시하려면 다음 3가지 방법이 있습니다.

  1. 네이티브 코드에서 JNI와 크래시를 사용합니다.
  2. Security Manager가 설치되어 있지 않은 경우 리플렉션 기능을 사용하여 VM을 크래시할 수 있습니다.이는 VM에 고유하지만 일반적으로 VM은 네이티브 리소스에 대한 포인터를 개인 필드에 저장합니다(예를 들어 네이티브 스레드 개체에 대한 포인터는 java.lang의 긴 필드에 저장됩니다).스레드).리플렉션으로 변경하기만 하면 머지않아 VM이 크래시 됩니다.
  3. 모든 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* 파일을 포함한 실제 크래시가 발생합니다.

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 - Xboot classpath / p : 。크래시

편집: 단순화된 버전으로 제안:

Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);

제가 여기 온 이유는 채드 파울러가 쓴 '열정 프로그래머'에서 이 질문을 우연히 접했기 때문입니다.카피에 액세스 할 수 없는 유저에게 있어서, 질문은 「매우 뛰어난 Java 프로그래머」를 필요로 하는 직책을 면접하는 후보자에 대한 필터/테스트의 일종으로 짜여져 있다.

구체적으로 그는 다음과 같이 묻는다.

Java Virtual Machine이 크래쉬하는 프로그램을 순수 Java로 작성하려면 어떻게 해야 합니까?

저는 자바에서 15년 넘게 프로그래밍을 해왔고, 이 질문은 혼란스러우면서도 불공평하다는 것을 알았습니다.다른 사람들이 지적한 바와 같이 Java는 관리 대상 언어로서 크래쉬하지 않도록 특별히 설계되었습니다.물론 JVM의 버그는 항상 존재하지만,

  1. 실제 가동 수준의 JRE가 15년 이상 지속된 후에는 거의 발생하지 않습니다.
  2. 이러한 버그는 다음 릴리스에서 패치될 가능성이 높기 때문에 프로그래머로서 현재 JRE의 show-stoppers 세트에 대한 자세한 내용을 참조할 가능성은 얼마나 됩니까?

다른 사람들이 언급했듯이 JNI를 통한 일부 네이티브 코드는 JRE를 크래시하는 확실한 방법입니다.하지만 저자가 순수 자바어로 구체적으로 언급했으므로, 이제 그만입니다.

다른 옵션은 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가 응답했습니다.

PS: 그 외에는 훌륭한 책입니다.나는 루비를 배우면서 도덕적인 지원을 위해 그것을 주웠다.

지난번에는 이렇게 해 봤더니

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을 위험한 방법으로 크래시합니다.

import sun.dc.pr.PathDasher; 

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

완벽한 JVM 구현은 중단되지 않습니다.

JVM을 크래시하려면 JNI 외에 VM 자체에서 버그를 찾아야 합니다.무한 루프는 CPU만 소비합니다.메모리를 무한 할당하면 적절하게 구축된 JVM에서 Out Of Memory Error가 발생합니다.이로 인해 다른 스레드에 문제가 발생할 수 있지만 정상적인 JVM은 여전히 크래시하지 않습니다.

VM의 소스 코드에서 버그가 발견되어 VM 구현의 메모리 사용량에서 세그멘테이션 장애가 발생하는 경우 실제로 버그를 크래시할 수 있습니다.

JVM을 크래시하려면 Sun JDK 1.6_23 이하에서 다음을 사용하십시오.

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

이는 Sun JDK의 버그로 인해 발생합니다.Open JDK에서도 볼 수 있습니다.이는 Oracle JDK 1.6_24 이후부터 수정되었습니다.

추락이 무슨 뜻인지에 따라 다르죠

무한 재귀로 스택 공간이 부족해지도록 할 수 있지만 "완벽하게" 충돌합니다.예외가 발생하지만 JVM이 모든 것을 처리합니다.

JNI를 사용하여 네이티브코드를 호출할 수도 있습니다.제대로 하지 않으면 세게 부딪힐 수 있어요.이러한 크래시의 디버깅은 「재밌다」(실제로, 서명된 Java 애플릿에서 호출하는 큰 C++ DLL을 쓸 필요가 있었습니다).:)

은 "답변"입니다.System.exit()JVM을 이용하다그러나 이와는 별도로 네이티브 코드와 자원 고갈이 가장 유력한 해결책입니다.또는 Sun의 버그 트래커에서 사용 중인 JVM 버전의 버그를 확인할 수 있으며, 그 중 일부는 반복 가능한 크래시 시나리오가 가능합니다.예전에는 32비트 버전에서는 메모리 용량이 4Gb에 육박하면 반정기적인 크래시가 발생하곤 했습니다(현재는 일반적으로 64비트를 사용하고 있습니다).

Jon Meyer의 저서 Java Virtual Machine에는 JVM을 코어 덤프하게 만든 일련의 바이트 코드 명령의 예가 있습니다.이 책의 복사본을 찾을 수가 없어요.혹시 아시는 분 있으면 찾아보고 올려주세요.

winxpsp2 w/wmp10 jre6 win 。0_7

Desktop.open(uriToAviOrMpg파일)

이로 인해 생성된 스레드가 수집되지 않은 Throwable을 던지고 핫스팟이 크래시됩니다.

YMMV

하드웨어가 고장나면 모든 프로그램이 크래시 됩니다.같은 설정으로 다른 머신에서 정상적으로 동작하고 있는 동안 특정 머신에서 재현 가능한 앱 크래시가 발생한 적이 있습니다.그 기계에는 램이 고장났다는 것이 밝혀졌습니다.

가능한 최단 경로:)

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

메모리가 부족한 것처럼 가장하고 싶은 경우 다음 작업을 수행할 수 있습니다.

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

네이티브 메서드(빌트된 메서드)를 호출하여 JVM에서 오류 파일을 덤프하는 방법은 몇 가지 알고 있지만, 이 방법을 모르는 것이 가장 좋습니다.;)

처리되지 않은 상황(예: Java 예외 또는 오류 없음)에 의해 크래시를 프로세스 중단으로 정의하면 Java 내에서 이를 수행할 수 없습니다(sun.misc를 사용할 권한이 없는 경우).안전하지 않은 클래스).이게 관리 코드의 전체 포인트입니다.

네이티브 코드의 일반적인 크래시는 잘못된 메모리 영역(늘 주소 또는 정렬 오류)에 대한 포인터의 참조 해제에 의해 발생합니다.또 다른 소스로는 잘못된 기계 명령(opcode) 또는 라이브러리 또는 커널 호출로부터의 처리되지 않은 신호가 있습니다.둘 다 JVM 또는 시스템 라이브러리에 버그가 있는 경우 트리거될 수 있습니다.

예: JIT화된(생성된) 코드, 네이티브 메서드 또는 시스템 호출(그래픽 드라이버)에 의해 실제 크래시가 발생할 수 있습니다(ZIP 기능을 사용하여 메모리가 부족할 경우 크래시가 발생하는 것은 매우 일반적입니다).이 경우 JVM의 크래시 핸들러가 시작되어 상태가 덤프됩니다.OS 코어 파일(Windows에서는 왓슨 박사, *nix에서는 코어 덤프)을 생성할 수도 있습니다.

Linux/Unix에서는 실행 중인 프로세스에 신호를 보내면 JVM 크래시를 쉽게 만들 수 있습니다.주의: 를 사용하지 마십시오.SIGSEGV이를 위해 핫스팟이 이 신호를 포착하여 Null Pointer로 재슬로우하기 때문에대부분의 장소에서는 예외입니다.그래서 더 좋은 방법은SIGBUS예를들면.

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분 후에, RAM을 주의해 주세요).

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:
# 

"crash"가 JVM이 hs_err_pid%p.log에 쓰도록 하는 등 JVM의 갑작스런 중단을 의미하는 경우 다음과 같이 할 수 있습니다.

- Xmx arg를 작은 값으로 설정하고 JVM에 강제로 메모리 부족에 크래시를 발생시키도록 지시합니다.

 -Xmx10m -XX:+CrashOnOutOfMemoryError

확실히 하자면 위의 두 번째 arg가 없으면 jvm이 Out Of Memory Error로 종료될 뿐 jvm을 "크래시"하거나 갑자기 중단하지는 않습니다.

이 기술은 JVM -XX:ErrorFile arg를 테스트하려고 했을 때 도움이 되었습니다.이 arg는 이러한 hs_err_pid 로그를 쓰는 위치를 제어합니다.나는 이 게시물을 발견했는데, 그러한 크래시를 강제할 방법을 찾던 중 이 게시물을 발견했다.나중에 위의 내용이 저의 요구에 가장 쉽게 맞는다는 것을 알게 되었을 때, 저는 이 목록에 추가하고 싶었습니다.

마지막으로, FWIW에서는 이미 arg에 -Xms 값이 설정되어 있는 경우(상기보다 큰 값으로) 테스트 할 수 있는 경우, 이 값을 삭제 또는 변경해야 합니다.또는 크래시가 아니라 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현재 프로세스의 메시지 파괴는 허용되지 않습니다.

for 루프의 무한을 같은 함수에 대한 재귀 호출로 변경하면 스택오버플로우 예외가 발생합니다.

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

public void causeStackOverflow() {
    causeStackOverflow();
}

지금 하고 있는데, 어떻게 하는지 잘 모르겠어요. :-) JVM(및 내 앱)이 완전히 사라질 때가 있어요.오류도 기록도 없습니다.경고 없이 즉시 작동에서 전혀 실행되지 않는 상태가 됩니다.

JVM 크래시를 복제할 때 이 문제가 발생합니다.

Jni는 작동하지만 다른 플랫폼에 맞게 조정해야 합니다.최종적으로 이 조합을 사용하여 JVM을 크래시합니다.

  1. 「JVM」으로 을 합니다.-XX:+CrashOnOutOfMemoryError
  2. 사용하다long[] l = new long[Integer.MAX_VALUE];

그러면 JVM이 크래시하여 크래시 로그를 생성합니다.

'크래시'가 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 타입에 따라 달라지나요?

언급URL : https://stackoverflow.com/questions/65200/how-do-you-crash-a-jvm

반응형