it-swarm-id.com

Bagaimana Anda menabrak JVM?

Saya sedang membaca buku tentang keterampilan pemrograman di mana penulis bertanya kepada orang yang diwawancarai, "Bagaimana Anda menabrak JVM?" Saya pikir Anda bisa melakukannya dengan menulis infinite untuk-loop yang pada akhirnya akan menggunakan semua memori.

Adakah yang punya ide?

141

Hal yang paling dekat dengan "jawaban" tunggal adalah System.exit() yang mengakhiri JVM segera tanpa pembersihan yang benar. Namun terlepas dari itu, kode asli dan kehabisan sumber daya adalah jawaban yang paling mungkin. Sebagai alternatif, Anda dapat mencari bug bug Sun di versi JVM Anda, beberapa di antaranya memungkinkan untuk skenario kerusakan berulang. Kami biasa mendapatkan crash semi-reguler ketika mendekati batas memori 4 Gb di bawah versi 32-bit (kami biasanya menggunakan 64-bit sekarang).

6
Leigh Caldwell

Saya tidak akan menyebut melempar OutOfMemoryError atau StackOverflowError crash. Ini hanya pengecualian normal. Untuk benar-benar crash VM ada 3 cara:

  1. Gunakan JNI dan crash dalam kode asli.
  2. Jika tidak ada manajer keamanan yang diinstal Anda dapat menggunakan refleksi untuk crash VM. Ini adalah VM spesifik, tetapi biasanya a VM menyimpan banyak pointer ke sumber daya asli di bidang pribadi (misalnya pointer ke objek thread asli disimpan di bidang panjang di Java.lang.Thread). Cukup ubah melalui refleksi dan VM akan macet cepat atau lambat.
  3. Semua VM memiliki bug, jadi Anda hanya perlu memicu satu.

Untuk metode terakhir saya punya contoh singkat, yang akan menabrak Sun Hotspot VM diam dengan baik:

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

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

Ini mengarah ke tumpukan overflow di GC sehingga Anda tidak akan mendapatkan StackOverflowError tetapi crash nyata termasuk file hs_err *.

172
ralfs

JNI . Bahkan, dengan JNI, menabrak adalah mode operasi standar. Anda harus bekerja ekstra keras agar tidak crash.

123
Dan Dyer

Gunakan ini:

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();
    }
}

Kelas ini harus di boot classpath karena menggunakan kode tepercaya, jadi jalankan seperti ini:

Java -Xbootclasspath/p :. Jatuh

56
Dave Griffiths

Saya datang ke sini karena saya juga mengalami pertanyaan ini di The Passionate Programmer , oleh Chad Fowler. Bagi mereka yang tidak memiliki akses ke salinan, pertanyaan dibingkai sebagai semacam filter/tes untuk kandidat yang mewawancarai posisi yang membutuhkan "benar-benar baik Java programmer."

Secara khusus, ia bertanya:

Bagaimana Anda menulis sebuah program, di Java murni, yang akan menyebabkan Java Virtual Machine lumpuh?

Saya telah memprogram dalam Java selama lebih dari 15 tahun, dan saya menemukan pertanyaan ini membingungkan dan tidak adil. Seperti yang telah ditunjukkan orang lain, Java, sebagai bahasa yang dikelola, dirancang khusus tidak sampai crash. Tentu saja selalu ada bug JVM, tetapi:

  1. Setelah 15+ tahun JRE tingkat produksi, jarang terjadi.
  2. Setiap bug seperti itu kemungkinan akan ditambal pada rilis berikutnya, jadi seberapa besar kemungkinan Anda sebagai seorang programmer untuk bertemu dan mengingat kembali rincian set-stop JRE saat ini?

Seperti yang lain telah disebutkan, beberapa kode asli melalui JNI adalah cara yang pasti untuk menabrak JRE. Tetapi penulis secara khusus menyebutkan dalam Java murni, jadi itu keluar.

Pilihan lain adalah memberi makan kode byte palsu JRE; cukup mudah untuk membuang beberapa data biner sampah ke file .class, dan meminta JRE untuk menjalankannya:

$ echo 'crap crap crap' > crap.class
$ Java crap
Exception in thread "main" Java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file crap

Apakah itu masuk hitungan? Maksudku JRE itu sendiri belum jatuh; itu benar mendeteksi kode palsu, melaporkannya, dan keluar.

Ini membuat kita dengan jenis solusi yang paling jelas seperti meniup tumpukan melalui rekursi, kehabisan memori tumpukan melalui alokasi objek, atau hanya melempar RuntimeException. Tapi ini hanya menyebabkan JRE keluar dengan StackOverflowError atau pengecualian serupa, yang, sekali lagi bukan benar-benar macet.

Jadi, apa yang tersisa? Saya benar-benar ingin mendengar apa yang sebenarnya ada dalam pikiran penulis sebagai solusi yang tepat.

Pembaruan : Chad Fowler merespons di sini .

PS: buku yang bagus. Saya mengambilnya untuk dukungan moral sambil belajar Ruby.

32
George Armhold

Kode ini akan merusak JVM dengan cara yang tidak menyenangkan

import Sun.dc.pr.PathDasher; 

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

Terakhir kali saya mencoba ini akan melakukannya:

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();
        }
    }
}

Bagian pertama dari file log yang dihasilkan:

#
# 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
17
Hot Licks

Implementasi JVM yang sempurna tidak akan pernah crash.

Untuk membuat crash JVM, selain dari JNI, Anda perlu menemukan bug di VM itu sendiri. Loop tak terbatas hanya mengkonsumsi CPU. Mengalokasikan memori yang tidak terbatas seharusnya hanya menyebabkan OutOfMemoryError's di JVM yang dibangun dengan baik. Ini mungkin akan menyebabkan masalah untuk utas lainnya, tetapi JVM yang baik tetap tidak crash.

Jika Anda dapat menemukan bug dalam kode sumber VM, dan misalnya menyebabkan kesalahan segmentasi dalam penggunaan memori implementasi VM, maka Anda benar-benar dapat crash.

15
Dave L.

Jika Anda ingin membuat crash JVM - gunakan yang berikut di Sun JDK 1.6_23 atau di bawah ini:

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

Ini karena bug di Sun JDK - juga ditemukan di OpenJDK. Ini diperbaiki dari Oracle JDK 1.6_24 dan seterusnya.

14

Tergantung pada apa yang Anda maksud dengan crash.

Anda dapat melakukan rekursi yang tak terbatas untuk membuatnya kehabisan ruang stack, tetapi itu akan crash "anggun". Anda akan mendapatkan pengecualian, tetapi JVM itu sendiri akan menangani semuanya.

Anda juga dapat menggunakan JNI untuk memanggil kode asli. Jika Anda tidak melakukannya dengan benar maka Anda dapat membuatnya sangat sulit. Debugging crash itu adalah "menyenangkan" (percayalah, saya harus menulis C++ besar DLL yang kita panggil dari applet Java yang ditandatangani). :)

10
Herms

Buku Java Virtual Machine oleh Jon Meyer memiliki contoh serangkaian instruksi bytecode yang menyebabkan JVM ke dump inti. Saya tidak dapat menemukan salinan buku ini. Jika ada orang di luar sana yang punya, silakan cari dan kirimkan jawabannya.

6
Soulfly

Perangkat keras yang rusak dapat merusak program apa pun. Saya pernah mengalami crash aplikasi yang dapat direproduksi pada mesin tertentu sambil bekerja dengan baik pada mesin lain dengan setup yang sama persis. Ternyata mesin itu memiliki RAM yang rusak.

5

Bukan crash, tapi lebih dekat ke crash daripada jawaban yang diterima menggunakan System.exit

Anda dapat menghentikan JVM dengan menelepon

Runtime.getRuntime().halt( status )

Menurut dokumen: -

"metode ini tidak menyebabkan kait shutdown untuk dimulai dan tidak menjalankan fininver yang tidak diinvasi jika finalisasi saat keluar telah diaktifkan".

5
henry

cara terpendek :)

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

pada winxpsp2 w/wmp10 jre6.0_7

Desktop.open (uriToAviOrMpgFile)

Hal ini menyebabkan thread yang muncul untuk melemparkan Throwable yang tidak tertangkap dan crash hotspot

YMMV

5
kitsuneymg

Jika Anda mendefinisikan crash sebagai proses batal karena situasi tidak tertangani (yaitu tidak Java Pengecualian atau Kesalahan), maka ini tidak dapat dilakukan dari dalam Java (kecuali jika Anda memiliki izin untuk menggunakan kelas Sun.misc.Unsafe). Ini adalah inti dari kode terkelola.

Kecelakaan umum dalam kode asli terjadi dengan mendeferensier pointer ke area memori yang salah (alamat nol atau tidak selaras). Sumber lain dapat berupa instruksi mesin ilegal (opcodes) atau sinyal tidak tertangani dari pustaka atau panggilan kernel. Keduanya dapat dipicu jika JVM atau pustaka sistem memiliki bug.

Misalnya kode JITed (dihasilkan), metode asli atau panggilan sistem (driver grafis) dapat memiliki masalah yang menyebabkan crash nyata (itu cukup umum untuk mendapatkan crash ketika Anda menggunakan fungsi Zip dan mereka kehabisan memori). Dalam kasus-kasus tersebut penangan kecelakaan JVM menendang dan membuang negara. Itu juga bisa menghasilkan file inti OS (Dr. Watson pada Windows dan core dump pada * nix).

Di Linux/Unix Anda dapat dengan mudah membuat crash JVM dengan mengirimkannya Sinyal ke proses yang sedang berjalan. Catatan: Anda tidak boleh menggunakan SIGSEGV untuk ini, karena Hotspot menangkap sinyal ini dan melemparkannya kembali sebagai NullPointerException di sebagian besar tempat. Jadi lebih baik mengirim SIGBUS misalnya.

4
eckes

di sini adalah penjelasan terperinci tentang apa yang menyebabkan JVM ke dump inti (mis. crash): http://kb.Adobe.com/selfservice/viewContent.do?externalId=tn_17534

4
COTOHA

Jika Anda ingin berpura-pura kehabisan memori, Anda bisa melakukannya

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

Saya tahu beberapa cara untuk menyebabkan JVM membuang file kesalahan dengan memanggil metode asli (yang dibangun di dalam), tetapi mungkin yang terbaik Anda tidak tahu bagaimana melakukan ini. ;)

3
Peter Lawrey

JNI adalah sumber besar gangguan. Anda juga dapat crash menggunakan antarmuka JVMTI karena itu perlu ditulis dalam C/C++ juga.

3
Jared

Jika Anda membuat proses utas yang secara tak terbatas menghasilkan lebih banyak utas (yang menghasilkan lebih banyak utas, yang ...) pada akhirnya Anda akan menyebabkan kesalahan stack overflow di JVM itu sendiri.

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();
    }
}

Ini memberi saya output (setelah 5 menit, perhatikan ram Anda)

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

Terpendek? Gunakan kelas Robot untuk memicu CTRL + BREAK. Saya melihat ini ketika saya mencoba untuk menutup program saya tanpa menutup konsol (Itu tidak memiliki fungsi 'keluar').

1
user6022288

Saya melakukannya sekarang, tetapi tidak sepenuhnya yakin bagaimana ... :-) JVM (dan aplikasi saya) kadang-kadang hilang sama sekali. Tidak ada kesalahan yang dilemparkan, tidak ada yang dicatat. Berganti dari bekerja menjadi tidak berjalan sama sekali secara instan tanpa peringatan.

0
Brian Knoblauch

Jika dengan "crash" yang Anda maksud adalah pembatalan JVM yang tiba-tiba, seperti yang akan menyebabkan JVM menulis ke hs_err_pid% p.log, Anda dapat melakukannya dengan cara ini.

Atur argumen-Xmx ke nilai yang sangat kecil dan beri tahu JVM untuk memaksakan crash pada outemmory:

 -Xmx10m -XX:+CrashOnOutOfMemoryError

Untuk menjadi jelas, tanpa argumen kedua di atas, itu hanya akan menghasilkan jvm terminating dengan OutOfMemoryError, tetapi itu tidak akan "crash" atau tiba-tiba membatalkan jvm.

Teknik ini terbukti membantu ketika saya mencoba untuk menguji JVM -XX: ErrorFile arg, yang mengontrol di mana log hs_err_pid harus ditulis. Saya telah menemukan posting ini di sini, ketika mencoba menemukan cara untuk memaksa crash seperti itu. Ketika saya kemudian menemukan hal di atas berfungsi sebagai yang termudah untuk kebutuhan saya, saya ingin menambahkannya ke daftar di sini.

Akhirnya, FWIW, jika ada yang dapat menguji ini ketika mereka sudah memiliki nilai -Xms yang ditetapkan di args Anda (ke beberapa nilai yang lebih besar dari di atas), Anda akan ingin menghapus atau mengubah itu juga, atau Anda tidak akan mendapatkan crash tetapi hanya kegagalan jvm untuk memulai, melaporkan "Ukuran tumpukan awal diatur ke nilai yang lebih besar dari ukuran tumpukan maksimum". (Itu tidak akan jelas jika menjalankan JVM sebagai layanan, seperti dengan beberapa server aplikasi. Sekali lagi, itu menggigit saya, jadi saya ingin membagikannya.)

0
charlie arehart

Apakah ini masuk hitungan?

long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}

Ini hanya berfungsi untuk Linux dan dari Java 9.

Untuk beberapa alasan saya tidak mengerti, ProcessHandle.current().destroyForcibly(); tidak membunuh JVM dan melempar Java.lang.IllegalStateException Dengan pesan menghancurkan proses saat ini tidak diizinkan.

0
mszmurlo