部署yingyourjavacodetoproductionlimitsyourtroubleshootingoptions.connectingtoyourappinproductionwithadebuggerisusuallllyoutof andyoumightnotevenbeabletogetconsoleaccess.soevenwithmonitoring,you’regoingtoenduptroubleshootingmanyproblemspost-mortiod
是的。 如果有堆栈跟踪的记录,那就太好了。 这就像一次性给你指南针、地图、头等舱机票一样! 讨论一下什么是Java堆栈跟踪,以及如何使用它吧。
什么是Java堆栈跟踪? 堆栈跟踪也称为堆栈回溯,或简称为回溯。 堆栈帧的列表。 这些帧表示正在执行APP应用程序的时间。 堆栈帧是有关代码调用的方法或函数的信息。 因此,Java堆栈跟踪是一个从当前方法开始并扩展到程序启动时的帧列表。
堆栈和堆栈之间可能会发生混乱。 一叠纸是数据结构,就像桌子上的一叠纸。 先进先出。 将文档添加到文件堆栈中,并按与置入顺序相反的顺序删除。 更确切地说,堆栈称为运行时或调用堆栈,是程序在运行时创建的一组堆栈帧,由堆栈数据结构组织而成。
请看一个例子。
Java堆栈跟踪示例看看Java程序。 此类调用四个方法,从最后一个方法开始将堆栈跟踪打印到控制台。
公共类堆栈跟踪{一种公共静态语音主(字符串[ ] args ) }; }静态void a () (b ); }静态void b () c ); )静态void c () d ); (静态void d ) ) { Thread.dumpStack; }上课时,可以看到以下内容。
java.lang.Exception :堆栈跟踪为java.base/Java.lang.thread.dumpstack (thread.Java :1383 )是com.ericgoebelbecker.stack traces.stack trace.d )堆栈跟踪. Java:19 )位于com.ericgoebelbecker.stack traces.stack trace.b ) stacktrace.Java339 )上的trace.a (stack trace.b ) 位于tacktrace.main ) stacktrace.Java33607 ) d )中的main (方法位于程序启动的位置,因此位于底部。 程序启动后,Java运行时执行main ()方法。 Main (称为a )。 a (为b ),b ) )为c ),后者为d )。 最后,称为d (是dumpStack ) )生成输出。 此Java堆栈跟踪提供了程序执行顺序的图像。
Java堆栈跟踪是一个瞬间的快照。 你可以知道APP应用程序在哪里,以及它是如何到达那里的。 这是宝贵的见解,可以使用几种不同的方法。
如何使用Java堆栈跟踪已验证是否显示Java堆栈跟踪,如何使用?
Java异常堆栈跟踪和异常通常是相互关联的。 当您看到Java APP应用程序引发异常时,通常会看到与其一起记录的堆栈跟踪。 这是异常是如何工作的?
当Java代码抛出异常时,它将查找具有处理程序的方法,该处理程序可以在运行时在堆栈中处理该异常。 如果找到一个的话,它会把异常传达给它。 否则,程序将退出。 因此,异常和调用栈是直接链接的。 了解这种关系有助于阐明代码为什么引起异常。
更改示例代码吧。
首先,d ) )修改方法。
静态void d ()新建nullpointerexception )“oops! ”); }然后修改main (和a )以允许main捕获异常。 必须将要检查的异常添加到a (,以便代码可以编译。
公共语音主(字符串[ ] args )尝试)一种); }抓住(InvalidClassException ice ) system.err.println (ice.getmessage ) ); }静态void a ()抛出InvalidClassExcept
ion { b(); }您故意抓住“错误”例外。 运行此代码,然后观察会发生什么。
线程“主”中的异常java.lang.NullPointerException:糟糕! 在com.ericgoebelbecker.stacktraces.StackTrace.d(StackTrace.java:29) 在com.ericgoebelbecker.stacktraces.StackTrace.c(StackTrace.java:24) 在com.ericgoebelbecker.stacktraces.StackTrace.b(StackTrace.java:20) 在com.ericgoebelbecker.stacktraces.StackTrace.a(StackTrace.java:16) 在com.ericgoebelbecker.stacktraces.StackTrace.main(StackTrace.java:9)异常使通过main()的堆栈冒泡,因为您试图捕获其他异常。 因此,运行时将其抛出,从而终止了应用程序。 不过,您仍然可以看到堆栈跟踪,因此很容易确定发生了什么。
现在,更改main()以捕获NullPointerException。 您也可以从a()中删除已检查的异常。
公共静态void main(String [] args){ 尝试{ 一种(); }抓(NullPointerException ice){ System.err.println(ice.getMessage()); } } 静态void a(){ b(); }重新运行程序。
糟糕!我们丢失了堆栈跟踪! 通过仅打印附加到异常的消息,您错过了一些重要的上下文。 除非你记得你为什么写糟糕!在该消息中,查找此问题将变得很复杂。 让我们再试一次。
公共静态void main(String [] args){ 尝试{ 一种(); } catch(NullPointerException npe){ npe.printStackTrace(); } }重新运行该应用程序。
java.lang.NullPointerException:糟糕! 在com.ericgoebelbecker.stacktraces.StackTrace.d(StackTrace.java:28) 在com.ericgoebelbecker.stacktraces.StackTrace.c(StackTrace.java:24) 在com.ericgoebelbecker.stacktraces.StackTrace.b(StackTrace.java:20) 在com.ericgoebelbecker.stacktraces.StackTrace.a(StackTrace.java:16) 在com.ericgoebelbecker.stacktraces.StackTrace.main(StackTrace.java:9)这样更好! 我们看到了堆栈跟踪,它在发生异常的d()处结束,即使main()打印了它。
记录Java堆栈跟踪如果您不想将错误消息打印到控制台,而是打印到日志文件,该怎么办? 好消息是,如果使用正确的参数调用大多数记录器,包括Log4j和Logback,它们将使用堆栈跟踪编写异常。
Pass in the exception object as the last argument to the message, without a formatting directive. So if you used Log4j or Logback with the sample code like this:
logger.error(“发生了什么坏事:”,npe);您会在日志文件中看到以下内容:
不好的事情发生了: java.lang.NullPointerException:糟糕! 在com.ericgoebelbecker.stacktraces.StackTrace.d(StackTrace.java:28) 在com.ericgoebelbecker.stacktraces.StackTrace.c(StackTrace.java:24) 在com.ericgoebelbecker.stacktraces.StackTrace.b(StackTrace.java:20) 在com.ericgoebelbecker.stacktraces.StackTrace.a(StackTrace.java:16) 在com.ericgoebelbecker.stacktraces.StackTrace.main(StackTrace.java:9)您可以对异常和堆栈跟踪进行的最好的操作之一就是记录它们,以便可以使用它们来隔离问题。 如果您习惯打印有用的日志消息,其中包含堆栈跟踪和日志索引等详细信息,则搜索工具(例如Scalyr)将成为故障排除工具包中最强大的工具之一。
Java调试器调试器通过控制程序的运行时并让您观察和控制它来进行工作。 为此,它向您显示了程序堆栈,并使您可以在任一方向上对其进行遍历。 在调试器中,与查看日志消息中的堆栈跟踪信息相比,您可以获得更完整的堆栈框架图。
让我们进行一些小的代码更改,然后将示例代码放入调试器。
首先,将局部变量添加到d()方法中:
静态void d(){ 字符串消息=“糟糕”。 抛出新的NullPointerException(message); }然后添加一个断点,其中d()在调试器中引发异常。 我正在为此图像使用IntelliJ的调试器。
在这里您可以看到我们添加到d()的字符串是堆栈框架的一部分,因为它是一个局部变量。 调试器在Stack内部运行,并为您提供每帧的详细图片。
强制线程转储线程转储是很棒的事后分析工具,但是它们对于运行时问题也很有用。 如果您的应用程序停止响应或消耗的CPU或内存超出您的预期,则可以通过以下方式检索有关正在运行的应用程序的信息:jstack。
修改main()以便应用程序运行直到被杀死:
公共静态void main(String [] args)引发异常{ 尝试{ while(true){ Thread.sleep(1000); } }抓(NullPointerException ice){ ice.printStackTrace(); } }运行该应用程序,确定其pid,然后运行jstack。 在Windows上,您需要按Ctrl中断在DOS窗口中,您正在其中运行代码。
$ jstack <pid>Jstack将产生大量输出。
too long我的应用程序正在运行11个线程,而jstack为所有这些线程生成了堆栈跟踪。 第一个线程(有用地命名为main)是我们关注的那个线程。 您可以看到它在wait()上处于休眠状态。
Java堆栈跟踪:您的路线图A stack trace is more than just a picture inside your application. It's a snapshot of a moment in time that includes every step your code took to get there. There's no reason to dread seeing one in your logs because they're a gift from Java that tells you exactly what happened. Make sure you're logging them when an error crops up and send them to a tool like Scalyr so they're easy to find.
Now that you understand what a Java stack trace is and how to use it, take a look at your code. Are you throwing away critical information about errors and exceptions in your code? Is there a spot where a call to Thread.dumpstack() might help you isolate a recurring bug? Perhaps it's time to run your app through the debugger a few times with some strategically-chosen breakpoints.
from: https://dev.to//scalyr/java-stack-trace-understanding-it-and-using-it-to-debug-5a3a