[我已经收到使用我编写的Java库的某人的日志,但令人困惑的是,堆栈跟踪未列出我方法的行号。
[This question似乎表明这意味着该类是在没有调试符号的情况下编译的,但是如果我从JAR中获取有问题的.class
文件,它们正在使用并在其上运行javap -v
,则可以看到该文件已在使用调试符号编译的事实,并且该方法有一个LineNumberTable:
LineNumberTable:
line 387: 0
line 389: 4
line 391: 11
line 393: 23
line 395: 30
line 397: 62
line 399: 69
line 412: 101
line 413: 107
line 414: 116
line 415: 122
line 416: 134
line 417: 141
line 418: 150
line 419: 156
line 421: 168
line 422: 178
line 423: 192
line 425: 206
line 431: 214
line 428: 217
line 430: 219
line 432: 224
所以我的问题变成了,即使我已经确认.class
文件具有调试符号,是什么导致行号不显示在stacktrace中?如果重要的话,这是在Android环境中。不,这不是ProGuard还是剥离调试符号的东西,因为行号在堆栈跟踪的其他部分列出。
所以我知道了。
快速说明,我可能应该在我的问题中提到这一点:有问题的堆栈跟踪不是崩溃/异常的结果,而是打印出来以显示看门狗杀死它之前线程在哪里,因为它没有反应。
synchronized
方法时,一个线程正在等待调用synchronized
方法时,堆栈跟踪的外观不同于ART与JVM!在ART上,顶部堆栈帧将显示为该方法中没有行号,但是在JVM中,它将显示为该方法中的第一行并带有行号。
这是Android的“完整,最小,可重现”的示例:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); launchThread("TH1"); sleep(100); launchThread("TH2"); sleep(20); dumpThreadTraces(); } void launchThread(String name) { Thread thread = new Thread(new Runnable() { @Override public void run() { doThings(); } }); thread.setName(name); thread.start(); } synchronized void doThings() { sleep(1000); } void dumpThreadTraces() { Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces(); Set<Thread> threads = traces.keySet(); for(Thread th : threads) { if(th.getName().startsWith("TH")) { logStackTrace(th, traces.get(th)); } } } void logStackTrace(Thread thread, StackTraceElement[] stackTrace) { System.out.printf("thread id=%d name=\"%s\"\n", thread.getId(), thread.getName()); logStackFrames(stackTrace); } void logStackFrames(StackTraceElement[] stackTrace) { for (StackTraceElement frame : stackTrace) { System.out.printf(" at %s\n", frame.toString()); } } void sleep(int millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行时,以下内容将打印到logcat:
I/System.out: thread id=2051 name="TH1" I/System.out: at java.lang.Thread.sleep(Native Method) I/System.out: at java.lang.Thread.sleep(Thread.java:371) I/System.out: at java.lang.Thread.sleep(Thread.java:313) I/System.out: at com.domain.helloworld.MainActivity.sleep(MainActivity.java:94) I/System.out: at com.domain.helloworld.MainActivity.doThings(MainActivity.java:58) I/System.out: at com.domain.helloworld.MainActivity$1.run(MainActivity.java:48) I/System.out: at java.lang.Thread.run(Thread.java:761) I/System.out: thread id=2052 name="TH2" I/System.out: at com.domain.helloworld.MainActivity.doThings(MainActivity.java) I/System.out: at com.domain.helloworld.MainActivity$1.run(MainActivity.java:48) I/System.out: at java.lang.Thread.run(Thread.java:761)
注意,对于线程2,如何不打印顶部堆栈跟踪元素的行号!
at com.domain.helloworld.MainActivity.doThings(MainActivity.java)