क्या जावा में एक अपवाद को फेंकने के बिना एक स्टैक ट्रेस को डंप करने का एक तरीका है?


159

मैं अपने जावा एप्लिकेशन के लिए डिबग टूल बनाने की सोच रहा हूं।

मैं सोच रहा हूं कि क्या स्टैक ट्रेस मिलना संभव है, जैसे कि Exception.printStackTrace()लेकिन वास्तव में अपवाद को फेंकने के बिना?

मेरा लक्ष्य, करने के लिए किसी भी विधि में, जो विधि फोन करने वाले है देखने के लिए एक ढेर डंप है।

जवाबों:


84

आप उन Thread.getAllStackTraces()सभी थ्रेड्स के लिए स्टैक के निशान का नक्शा प्राप्त करने का प्रयास कर सकते हैं जो जीवित हैं।


250

हाँ, बस का उपयोग

Thread.dumpStack()

44
... लेकिन यह फेंक नहीं है।
रोब

5
यह वह उत्तर है जो वास्तव में प्रश्न को संबोधित करता है।
ब्रूनो

7
बहुत सरल और सुरुचिपूर्ण। यह स्वीकृत उत्तर होना चाहिए था।
deLock

11
Fwiw, इस विधि का स्रोत: public static void dumpStack() { new Exception("Stack trace").printStackTrace(); }
JohnK

यदि आप आउटपुट के साथ खुश हैं, तो यह प्रश्न का सबसे अच्छा उत्तर है stderr, जो प्रश्न का निहितार्थ प्रतीत होता है।
माइक कृंतक

46

यदि आप केवल वर्तमान थ्रेड के लिए ट्रेस चाहते हैं (सिस्टम के सभी थ्रेड्स के बजाय, जैसा कि राम का सुझाव है), करें:

Thread.currentThread ()। getStackTrace ()

कॉलर को खोजने के लिए, करें:

private String getCallingMethodName() {
    StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
    return callingFrame.getMethodName();
}

और उस विधि को उस विधि के भीतर से कॉल करें जिसे यह जानने की आवश्यकता है कि उसका कॉलर कौन है। हालाँकि, चेतावनी का एक शब्द: सूची के भीतर कॉलिंग फ़्रेम का सूचकांक JVM के अनुसार भिन्न हो सकता है! यह सब इस बात पर निर्भर करता है कि जब आप ट्रेस जेनरेट करते हैं, तो बिंदु पर जाने से पहले गेटस्टैक्स के भीतर कॉल की कितनी परतें हैं। ट्रेस प्राप्त करने के लिए एक अधिक मजबूत समाधान होगा, और getCallingMethodName के लिए फ्रेम की तलाश में इसे पुन: व्यवस्थित करें, फिर सच्चे कॉलर को खोजने के लिए दो कदम आगे बढ़ें।


2
तो बस अपने दम पर एक नया अपवाद बनाएं और इंडेक्स के रूप में [1] का उपयोग करें!
डैनियल

3
इस सवाल का शीर्षक "बिना किसी अपवाद को फेंकने" है। दी, आप अपवाद बनाने का सुझाव देते हैं लेकिन इसे फेंकने का नहीं, लेकिन मुझे लगता है कि यह सवाल की भावना में नहीं है।
टॉम एंडरसन

1
निश्चित रूप से यह है। स्टैकट्रेस प्राप्त करने के लिए एक अपवाद बनाना सबसे कम तरीका है। यहां तक ​​कि आपके Thread.currentThread ()। GetStackTrace () इसे करता है, लेकिन मेरा तरीका इसे और तेज करता है :)।
डैनियल

@ डैनियल एक और विचार है: कई परीक्षण रूपरेखाओं के साथ, उदाहरण के लिए, स्पोक, बस एक अपवाद बनाना (इसे फेंकने के बिना) फ्रेमवर्क को चुनने के लिए पर्याप्त होगा: परीक्षण तब विचार करेगा कि एक अपवाद "हुआ" और परीक्षण अंत, एक असफलता के साथ।
माइक कृंतक

@mikerodent: क्या आप सुनिश्चित हैं? ऐसा करने के लिए स्पॉक को एजेंटों का उपयोग करना होगा। लेकिन फिर भी, क्योंकि मुझे सिर्फ क्लास में कॉल करने की ज़रूरत थी मैंने एक उपयोगिता फ़ंक्शन में Reflection.getCallerClass (2) का उपयोग किया। आपको फ़ंक्शन और लाइन नंबर इस तरह से नहीं मिलेंगे, सोचा।
डैनियल

37

आप इस तरह से स्टैक ट्रेस प्राप्त कर सकते हैं:

Throwable t = new Throwable();
t.printStackTrace();

यदि आप फ़्रेम को एक्सेस करना चाहते हैं, तो स्टैक फ़्रेम की एक सरणी प्राप्त करने के लिए t.getStackTrace () का उपयोग कर सकते हैं।

ध्यान रखें कि इस स्टैकट्रेस (किसी भी अन्य की तरह) कुछ फ्रेम गायब हो सकता है अगर हॉटस्पॉट संकलक व्यस्त अनुकूलन बातें किया गया है।


मुझे यह उत्तर पसंद है क्योंकि यह मुझे आउटपुट निर्देशित करने का अवसर प्रदान करता है। मैं के t.printStackTraceसाथ बदल सकते हैं t.printStackTrace(System.out)

4
एक पंक्ति में:new Throwable().printStackTrace(System.out);

1
यह स्वीकृत उत्तर होना चाहिए। यह सरल और सीधे आगे है! साझा करने के लिए धन्यवाद
सैम

2
और java.util.ogger को भेजना आसान हैlog.log(Level.SEVERE, "Failed to do something", new Throwable());
MitchBroadhead


6

आप JVM को एक रनिंग जावा प्रक्रिया पर Thread.getAllStackTraces () को निष्पादित करने के लिए एक सिग्नल भेज सकते हैं, प्रक्रिया को एक QUIT सिग्नल भेजकर।

यूनिक्स / लिनक्स उपयोग पर:

kill -QUIT process_id, जहां process_id आपके जावा प्रोग्राम की प्रक्रिया संख्या है।

विंडोज पर, आप एप्लिकेशन में Ctrl-Break दबा सकते हैं, हालांकि आप आमतौर पर इसे तब तक नहीं देखेंगे जब तक आप कंसोल प्रक्रिया नहीं चला रहे हैं।

JDK6 ने एक और विकल्प पेश किया, jstack कमांड, जो आपके कंप्यूटर पर चल रहे JDK6 प्रक्रिया से स्टैक को प्रदर्शित करेगा:

jstack [-l] <pid>

ये विकल्प उन अनुप्रयोगों के लिए बहुत उपयोगी हैं जो उत्पादन वातावरण में चल रहे हैं और इन्हें आसानी से संशोधित नहीं किया जा सकता है। वे रनटाइम गतिरोध या प्रदर्शन समस्याओं के निदान के लिए विशेष रूप से उपयोगी हैं।

http://java.sun.com/developer/technicalArticles/Programming/Stacktrace/ http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html



6

जावा 9 पेश किया StackWalker स्टैक चलने के लिए सहायक कक्षाएं कीं।

यहाँ जवादोक से कुछ स्निपेट दिए गए हैं:

walkविधि का एक अनुक्रमिक धारा खोलता StackFramesवर्तमान थ्रेड के लिए और फिर चलने के लिए दिए गए समारोह लागू होता है StackFrameधारा। धारा क्रम में स्टैक फ्रेम तत्वों की रिपोर्ट करती है, सबसे ऊपरी फ्रेम से जो निष्पादन बिंदु का प्रतिनिधित्व करता है जिस पर स्टैक नीचे सबसे फ्रेम में उत्पन्न हुआ था। StackFrameधारा जब टहलने के विधि रिटर्न बंद कर दिया है। यदि बंद धारा का पुन: उपयोग करने का प्रयास किया जाता है, IllegalStateExceptionतो उसे फेंक दिया जाएगा।

...

  1. वर्तमान थ्रेड के शीर्ष 10 स्टैक फ़्रेम को स्नैपशॉट करने के लिए,

    List<StackFrame> stack = StackWalker.getInstance().walk(s ->
     s.limit(10).collect(Collectors.toList()));

0

HPROF Java Profiler

आपको कोड में भी ऐसा नहीं करना है। आप अपनी प्रक्रिया में जावा एचपीआरओएफ को जोड़ सकते हैं और किसी भी बिंदु पर कंट्रोल- \ से आउटपुट हीप डंप, रनिंग थ्रेड आदि कर सकते हैं। । । अपने आवेदन कोड को मिटाए बिना। यह थोड़ा पुराना है, जावा 6 जीयूआई जोंको कंसोल के साथ आता है, लेकिन मुझे अभी भी एचपीआरओएफ बहुत उपयोगी लगता है।


0

रोब डि मार्को द्वारा जवाब अब तक का सबसे अच्छा है अगर आप के लिए उत्पादन के लिए खुश हैं stderr

यदि आप Stringएक सामान्य ट्रेस के अनुसार नई लाइनों के साथ कब्जा करना चाहते हैं , तो आप ऐसा कर सकते हैं:

Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.