Java类是用调试符号编译的,但是堆栈跟踪中没有显示行号?

问题描述 投票:0回答:1

[我已经收到使用我编写的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还是剥离调试符号的东西,因为行号在堆栈跟踪的其他部分列出。

java android stack-trace bytecode debug-symbols
1个回答
0
投票

所以我知道了。

快速说明,我可能应该在我的问题中提到这一点:有问题的堆栈跟踪不是崩溃/异常的结果,而是打印出来以显示看门狗杀死它之前线程在哪里,因为它没有反应。

  1. 如果不是死锁,那至少是由于长线程争用引起的>>
  2. [当另一个线程正在执行另一个synchronized方法时,一个线程正在等待调用synchronized方法时,堆栈跟踪的外观不同于ART与JVM!
  3. 在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)
© www.soinside.com 2019 - 2024. All rights reserved.