JVM何时会在堆栈跟踪中省略行信息,如何避免?

5
我有一个非常混乱的情况:
我有一个带行信息编译的类(使用javap -l进行验证)。该类被加载并使用ASM进行仪器化。我验证了正确的类被加载(即不是来自其他地方的过时类文件)。而且,我还确保ASM标志ClassReader.SKIP_DEBUG未设置。现在,如果我调用Thread.currentThread().getStackTrace(),我将得到有关此类的StackTraceElement,其中缺少行信息。在Eclipse中调试时,堆栈跟踪中显示行信息。我还确保JVM以-Xint启动,只是为了确保在代码被JIT编译时,不会因为优化而擦除信息。
最令人困惑的是:尽管所有类都被加载和仪器化,但这仅适用于某些类,而不是所有类。这就是我认为这与JVM有关的主要原因。
所以我的问题是:JVM是否省略堆栈跟踪中的行信息,如果是,请问何时以及如何防止这种情况发生?
编辑:仅为使事情清晰明了:这是面前源文件的类文件,而不是第三方库的类文件。正如上文所述,我努力确保信息在字节码中。
编辑:现在,我甚至找到了一个例子,其中一个StackTraceElement具有行号信息,而另一个没有,并且它们涉及来自同一类的不同方法!

省略行号的类是否有共同点(相同的包/ jar)? - TMN
1
你在进行仪器化吗?如果是的话,你是否更新了 LineNumberTable 来补偿你添加的任何字节码? - parsifal
1
我不熟悉ASM,但你能否以某种方式拦截它的类加载并在传递给defineClass()之前转储类的字节数组? - biziclop
1
@roesslerj - LineNumberTable 属性将字节码偏移量与行号关联起来。如果表中的字节码偏移量与被调用的代码不对应,我可以想象 JVM 会感到困惑(尽管我期望它只会给出错误的行号)。 - parsifal
1
我的猜测是,你的更改让JVM在确定与某些代码相关联的行号时感到困惑。 - Peter Lawrey
显示剩余5条评论
3个回答

1

这与类文件的编译方式有关。请在此处查看:

http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javac.html

在-g标志周围查找“调试信息”。如果添加-g,则代码将包含行号(以及许多其他有用的信息)。

很遗憾,这不会向第三方库中回溯添加调试信息。您必须查看源代码或从供应商获取调试版本。我发现通常不需要这样做。


很抱歉我没有表达清楚。我不是在谈论任何其他人的代码,而是我面前正在尝试调试的代码。我已经非常努力地确保字节码中有可用的信息... - roesslerj
编译项目时,必须在javac后面添加-g。 - PaulProgrammer

1
我在想你的堆栈跟踪报告中所报告的行(或没有报告,因为ASM修改了你的类)是否是ASM在操作你的类时生成的。由于它们是在编译后进行修改的,所以任何行号都不会出现在类文件中,因此它们将无法被类加载器使用(或者通过javap报告)。 我对运行时代码生成没有太多经验,所以这只是一个猜测,但也许这是你可以考虑的事情。

你是对的。一个代码行中可以有任意多个BytecodeInstructions(例如,可以将HelloWorld写在1行中),这就是为什么我没有特别处理的原因。但是ASM有LineNumberNodes作为伪BytecodeInstructions,如果代码添加到第一个LineNumberNode之前,则重新生成的LineNumberTable仅在生成的代码之后开始,因此添加的代码基本上没有行号信息。 - roesslerj

0

并非所有的行号都可以在JVM中使用。一些第三方库可能会在没有行号的情况下编译,特别是那些非开源的库,甚至有些Java类也有受保护的源代码,用于加密或其他受保护的逻辑。简而言之,并不是所有的东西都会有行号。


很抱歉我的表述不够清楚。我不是在谈论别人的代码,而是我面前正在尝试调试的代码。我已经很努力地确保信息在字节码中是可用的... - roesslerj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接