Java класс был скомпилирован с символами отладки, но номер строки не отображается в stacktrace? - PullRequest
1 голос
/ 11 февраля 2020

Я получил журнал от кого-то, использующего библиотеку 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 или что-то такое, что убирает символы отладки, потому что номера строк перечислены в других частях трассировки стека.

1 Ответ

1 голос
/ 25 февраля 2020

Итак, я понял это.

Небольшая заметка, и я, вероятно, должен был упомянуть об этом в своем вопросе: рассматриваемая трассировка стека не была результатом сбоя / исключения, а скорее была напечатана в покажите, где был поток до того, как сторожевой таймер убил его, потому что он не отвечал.

  1. Если это не тупик, то он был вызван, по крайней мере, конфликтом длинных потоков
  2. Что за трассировка стека выглядит так, когда поток ожидает вызова метода 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)
...