java - Java 类是用调试符号编译的,但堆栈跟踪中没有显示行号?
问题描述
我收到了来自使用我编写的 Java 库的人的日志,但令人困惑的是,堆栈跟踪没有列出我的方法的行号。
这个问题似乎表明该类是在没有调试符号的情况下编译的,但是如果我.class
从他们正在使用的 JAR 中获取有问题的文件并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
文件具有调试符号,什么可能导致行号不显示在堆栈跟踪中?如果重要的话,这是在 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)
推荐阅读
- c++ - 有谁知道我是否可以使用 CImg 和 C++ 在图像窗口上绘图?
- makefile - 如何更改 Makefile $(shell ...) 命令的 PATH?
- php - 如何使用自定义字符集递增字符串
- python - 需要帮助重写 python 2.7 Unicode 代码以使用 3.x
- c# - 当限制已包含接口时,在泛型类型限制中使用类子句
- json - 尽管对象不为空,但 Spring 仍发送空 JSON
- pandas - 熊猫数据集中的多个多值列 - 想要制作多行
- angular - 登录后加载实体,并导航到 entityID
- apache - 在多个httpd代理后面运行tomcat,如何记录请求经过哪个代理服务器的IP
- excel - VBA Vlookup 类型不匹配