मैं प्रोग्रामिंग कौशल पर एक किताब पढ़ रहा था जिसमें लेखक साक्षात्कारकर्ता से पूछता है, "आप एक जेवीएम को कैसे दुर्घटनाग्रस्त करते हैं?" मुझे लगा कि आप अनंत-पाश लिखकर ऐसा कर सकते हैं जो अंततः सभी मेमोरी का उपयोग करेगा।
किसी को भी किसी भी विचार है?
मैं प्रोग्रामिंग कौशल पर एक किताब पढ़ रहा था जिसमें लेखक साक्षात्कारकर्ता से पूछता है, "आप एक जेवीएम को कैसे दुर्घटनाग्रस्त करते हैं?" मुझे लगा कि आप अनंत-पाश लिखकर ऐसा कर सकते हैं जो अंततः सभी मेमोरी का उपयोग करेगा।
किसी को भी किसी भी विचार है?
जवाबों:
एक एकल "उत्तर" के लिए निकटतम चीज़ System.exit()जो उचित सफाई के बिना तुरंत जेवीएम को समाप्त करती है। लेकिन इसके अलावा, मूल कोड और संसाधन थकावट सबसे संभावित उत्तर हैं। वैकल्पिक रूप से आप JVM के अपने संस्करण में बग्स के लिए सन बग ट्रैकर को देख सकते हैं, जिनमें से कुछ दोहराए जाने वाले क्रैश परिदृश्यों के लिए अनुमति देते हैं। 32-बिट संस्करणों के तहत 4 जीबी मेमोरी सीमा के पास पहुंचने पर हम सेमी-रेगुलर क्रैश प्राप्त करते थे (हम आमतौर पर अब 64-बिट का उपयोग करते हैं)।
मैं OutOfMemoryError या StackOverflowError को क्रैश कहते हुए नहीं फेंकूंगा। ये सिर्फ सामान्य अपवाद हैं। VM को वास्तव में क्रैश करने के 3 तरीके हैं:
अंतिम विधि के लिए मेरे पास एक छोटा उदाहरण है, जो एक सन हॉटस्पॉट वीएम को चुपचाप दुर्घटनाग्रस्त कर देगा:
public class Crash {
public static void main(String[] args) {
Object[] o = null;
while (true) {
o = new Object[] {o};
}
}
}
यह जीसी में एक स्टैक ओवरफ्लो की ओर जाता है ताकि आपको कोई StackOverflowError नहीं मिलेगी लेकिन एक वास्तविक दुर्घटना जिसमें hs_err * फ़ाइल शामिल है।
java.lang.OutOfMemoryError: GC overhead limit exceeded
जेएनआई । वास्तव में, जेएनआई के साथ, दुर्घटनाग्रस्त होना ऑपरेशन का डिफ़ॉल्ट मोड है। दुर्घटना न हो इसके लिए आपको अतिरिक्त मेहनत करनी होगी।
इसे इस्तेमाल करो:
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लिनक्स x64 पर JDK 8u131 में ट्रिक का उपयोग करके काम करने की पुष्टि की , जिसमें hs_err_pid*.logसे a का उत्पादन भी शामिल है SIGSEGV।
Unsafeधोखा नहीं है। ओपी एक प्रोग्रामिंग समस्या के 'क्लीन' समाधान की तलाश नहीं कर रहा है। उसे सबसे कम संभव तरीके से दुर्घटनाग्रस्त होने के लिए जेवीएम की आवश्यकता होती है। बुरा देशी चीजें करना वह है जो ऐसा कर सकता है, और यह वास्तव में यही Unsafeकरता है।
मैं यहाँ आया क्योंकि मैं भी पैशन प्रोग्रामर में इस सवाल पर भागा था में चाड फाउलर द्वारा । उन लोगों के लिए जिनके पास एक कॉपी तक पहुंच नहीं है, इस प्रश्न को "वास्तव में अच्छे जावा प्रोग्रामर" की आवश्यकता वाले पद के लिए साक्षात्कार देने वाले उम्मीदवारों के लिए एक प्रकार के फ़िल्टर / परीक्षण के रूप में तैयार किया गया है।
विशेष रूप से, वह पूछता है:
आप शुद्ध जावा में एक प्रोग्राम कैसे लिखेंगे, जिससे जावा वर्चुअल मशीन क्रैश हो जाएगी?
मैंने 15 वर्षों के लिए जावा में प्रोग्राम किया है, और मुझे यह सवाल हैरान और अनुचित दोनों लगा। जैसा कि अन्य ने बताया है, जावा, एक प्रबंधित भाषा के रूप में, विशेष रूप से दुर्घटनाग्रस्त न होने के लिए डिज़ाइन किया गया है । बेशक वहाँ हमेशा JVM कीड़े हैं, लेकिन:
जैसा कि दूसरों ने उल्लेख किया है, जेएनआई के माध्यम से कुछ मूल कोड जेआरई को क्रैश करने का एक निश्चित तरीका है। लेकिन लेखक ने विशेष रूप से शुद्ध जावा में उल्लेख किया है , इसलिए यह बाहर है।
एक और विकल्प होगा जेआरई बोगस बाइट कोड्स को खिलाना; .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या समान अपवाद के साथ बाहर निकलने का कारण बनता है, जो फिर से वास्तव में दुर्घटना नहीं है ।
तो क्या बचा है? मैं वास्तव में एक उचित समाधान के रूप में लेखक के मन में क्या सुनना पसंद करूंगा।
अपडेट : चाड फाउलर ने यहां जवाब दिया ।
पुनश्च: यह एक अन्यथा महान पुस्तक है। रूबी को सीखते हुए मैंने इसे नैतिक समर्थन के लिए चुना।
यह कोड JVM को गंदे तरीकों से दुर्घटनाग्रस्त करेगा
import sun.dc.pr.PathDasher;
public class Crash
{
public static void main(String[] args)
{
PathDasher dasher = new PathDasher(null) ;
}
}
InternalErrorJDK 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 कार्यान्वयन कभी भी दुर्घटनाग्रस्त नहीं होगा।
JNI से अलग एक JVM को क्रैश करने के लिए, आपको VM में ही एक बग ढूंढना होगा। एक अनंत लूप सिर्फ सीपीयू की खपत करता है। असीम रूप से मेमोरी को आवंटित करने के कारण आउटऑफमेमोरी एरर का निर्माण अच्छी तरह से निर्मित जेवीएम में होना चाहिए। यह संभवतः अन्य थ्रेड्स के लिए समस्याएँ पैदा करेगा, लेकिन एक अच्छा JVM अभी भी क्रैश नहीं होना चाहिए।
यदि आप VM के स्रोत कोड में एक बग पा सकते हैं, और उदाहरण के लिए VM के कार्यान्वयन की स्मृति उपयोग में एक विभाजन दोष का कारण बनता है, तो आप वास्तव में इसे क्रैश कर सकते हैं।
यदि आप JVM को क्रैश करना चाहते हैं, तो Sun JDK 1.6_23 या उससे नीचे का उपयोग करें:
Double.parseDouble("2.2250738585072012e-308");
यह सूर्य JDK में एक बग के कारण है - OpenJDK में भी पाया जाता है। यह Oracle JDK 1.6_24 से तय होता है।
आप दुर्घटना से क्या मतलब है पर निर्भर करता है।
आप इसे स्टैक स्थान से बाहर चलाने के लिए एक अनंत पुनरावृत्ति कर सकते हैं, लेकिन यह "शान से" क्रैश हो जाएगा। आपको एक अपवाद मिलेगा, लेकिन JVM स्वयं सब कुछ संभाल रहा होगा।
आप देशी कोड को कॉल करने के लिए जेएनआई का भी उपयोग कर सकते हैं। यदि आप इसे सही नहीं करते हैं, तो आप इसे कठिन बना सकते हैं। उन क्रैश को डीबग करना "मजेदार" है (मुझ पर विश्वास करें, मुझे एक बड़ा सी ++ डीएलएल लिखना था जिसे हम एक हस्ताक्षरित जावा ऐप से कहते हैं)। :)
जॉन मेयर की पुस्तक जावा वर्चुअल मशीन में बायटेकोड निर्देशों की एक श्रृंखला का एक उदाहरण है जो जेवीएम को कोर डंप करने का कारण बना। मुझे इस पुस्तक की प्रति नहीं मिल रही है। अगर किसी के पास कोई है तो कृपया उसे देखें और उत्तर पोस्ट करें।
winxpsp2 w / wmp10 jre6.0_7 पर
Desktop.open (uriToAviOrMpgFile)
यह एक थ्रेडेड थ्रेडेबल को फेंकने और हॉटस्पॉट को क्रैश करने के लिए एक स्पैन्ड थ्रेड का कारण बनता है
YMMV
टूटा हुआ हार्डवेयर किसी भी प्रोग्राम को क्रैश कर सकता है। मैंने एक बार एक विशिष्ट मशीन पर एक ऐप क्रैश को ठीक उसी सेटअप के साथ अन्य मशीनों पर ठीक से चलाने के दौरान क्रैश कर दिया था। पता चलता है कि मशीन में दोषपूर्ण रैम था।
एक दुर्घटना नहीं है, लेकिन उपयोग करने के स्वीकृत उत्तर की तुलना में दुर्घटना के करीब है System.exit
आप कॉल करके JVM को रोक सकते हैं
Runtime.getRuntime().halt( status )
डॉक्स के अनुसार: -
"यह विधि शटडाउन हुक शुरू करने का कारण नहीं बनती है और यदि अंतिम-ऑन-एग्जिट सक्षम हो गई है तो बिन बुलाए फाइनल नहीं चलती है"।
जेवीएम को कोर डंप (यानी दुर्घटना) का कारण क्या है, इस पर एक विस्तृत विवरण दिया गया है: http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534
यदि आप दिखावा करना चाहते हैं तो आप स्मृति से बाहर भाग सकते हैं जो आप कर सकते हैं
public static void main(String[] args) {
throw new OutOfmemoryError();
}
मुझे पता है कि JVM को मूल तरीकों (जो में बनाया गया है) को कॉल करके एक त्रुटि फ़ाइल को डंप करने का एक तरीका पता है, लेकिन इसका सबसे अच्छा शायद आपको पता नहीं है कि यह कैसे करना है। ;)
यदि आप एक अनहेल्दी स्थिति (अर्थात कोई जावा अपवाद या त्रुटि) के कारण किसी क्रैश को प्रक्रिया निरस्त के रूप में परिभाषित करते हैं, तो यह जावा के भीतर से नहीं किया जा सकता है (जब तक कि आपको sun.misc.Unsafe वर्ग का उपयोग करने की अनुमति न हो)। यह प्रबंधित कोड का पूरा बिंदु है।
मूल कोड में विशिष्ट दुर्घटनाएँ डी-रेफ़रिंग पॉइंटर्स द्वारा गलत मेमोरी क्षेत्रों (अशक्त पते या गलत संदेश) के द्वारा होती हैं। एक अन्य स्रोत अवैध मशीन निर्देश (ऑपकोड) या लाइब्रेरी या कर्नेल कॉल से अनचाहे सिग्नल हो सकते हैं। JVM या सिस्टम लाइब्रेरी में बग होने पर दोनों को ट्रिगर किया जा सकता है।
उदाहरण के लिए JITed (जनरेट किया गया) कोड, देशी तरीके या सिस्टम कॉल (ग्राफिक्स ड्राइवर) से वास्तविक क्रैश की समस्याएँ हो सकती हैं (जब आप ZIP फ़ंक्शन का उपयोग करते हैं और वे मेमोरी से बाहर चले जाते हैं तो क्रैश प्राप्त करना काफी सामान्य था)। उन मामलों में जेवीएम का क्रैश हैंडलर राज्य को चकमा देता है। यह एक OS कोर फ़ाइल (Windows पर डॉ। वाटसन और * nix पर कोर डंप) भी उत्पन्न कर सकता है।
लिनक्स / यूनिक्स पर आप इसे चलाने की प्रक्रिया के लिए सिग्नल भेजकर आसानी से एक जेवीएम क्रैश कर सकते हैं। नोट: आपको इसके 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:
#
यदि "क्रैश" से आपका मतलब है कि जेवीएम का अचानक गर्भपात, जैसे कि जेवीएम को उसके hs_err_pid% p.log पर लिखना होगा। , तो आप इसे इस तरह से कर सकते हैं।
एक छोटे से मूल्य पर X-Xmx arg को सेट करें और JVM को एक दुर्घटना को रोकने के लिए कहें:
-Xmx10m -XX:+CrashOnOutOfMemoryError
स्पष्ट होने के लिए, ऊपर दिए गए दूसरे आर्ग के बिना, यह सिर्फ jvm को समाप्त करने में परिणाम देगा साथ , लेकिन यह जेवीएम को "क्रैश" या अचानक समाप्त नहीं करेगा।
यह तकनीक तब मददगार साबित हुई जब मैं JVM -XX का परीक्षण करने का प्रयास कर रहा था: ErrorFile arg, जो इस तरह के hs_err_pid लॉग को लिखने के लिए नियंत्रित करता है। इस तरह की दुर्घटना को रोकने के तरीके खोजने की कोशिश करते हुए मुझे यह पोस्ट यहाँ मिली थी। जब मैंने बाद में पाया कि मेरी जरूरत के लिए सबसे आसान के रूप में काम किया है, तो मैं इसे यहां सूची में जोड़ना चाहता था।
अंत में, एफडब्ल्यूआईडब्ल्यू, अगर कोई भी इसका परीक्षण कर सकता है, जब उनके पास पहले से ही एक -Xms मूल्य आपके args (ऊपर से कुछ बड़ा मूल्य) में सेट है, तो आप उसे भी निकालना या बदलना चाहेंगे, या आपको दुर्घटना नहीं होगी, लेकिन बस शुरू करने के लिए 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) {}
यह केवल लिनक्स के लिए और जावा 9 से काम करता है।
किसी कारण से, मुझे नहीं मिलता है, ProcessHandle.current().destroyForcibly();जेवीएम को मारना नहीं है और वर्तमान प्रक्रियाjava.lang.IllegalStateException के संदेश को नष्ट करने की अनुमति नहीं देता है ।
JVM क्रैश को दोहराने की कोशिश करते समय इस मुद्दे पर चल रहा है।
जानी काम करती है, लेकिन इसे अलग-अलग प्लेटफॉर्म के लिए ट्विस्ट करने की जरूरत है। आखिरकार, मैं इस संयोजन का उपयोग जेवीएम क्रैश करने के लिए करता हूं
-XX:+CrashOnOutOfMemoryErrorlong[] l = new long[Integer.MAX_VALUE];OOM को ट्रिगर करने के लिए a का उपयोग करेंतब जेवीएम क्रैश हो जाएगा और क्रैश लॉग उत्पन्न करेगा।
यदि कोई 'क्रैश' सामान्य समाप्ति से 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है