1

在正常执行之前,我需要检测本机方法以进行简单的静态调用。因为这些方法是原生的,所以我必须使用“setNativePrefix”功能,并使用带有原始方法签名的中间调用来包装原生方法。

在我认为是一个简单的字节码更改来完成此操作之后,即使堆栈基本上是空的,我也会在包装方法执行之前得到一个 StackOverflowError 。这是我的测试课:

public class SimpleTest {
    public static void main(String[] args) throws IOException {
        Perf.getPerf().highResCounter();
    }
}

通常,该程序不会在控制台上产生任何结果。但是,我的检测字节码在执行本机方法 $wrapper$highResCounter() 之前执行 println()。这可以在检测后的相关 Perf 类字节码中看到:

public long highResCounter() {
    getstatic PrintStream System.out
    ldc String Constant "this is an instrumented println"
    invokevirtual void PrintStream.println(String)
    aload 0
    invokevirtual long Perf.$wrapped$highResCounter()
    lreturn
}

public native long $wrapped$highResCounter();

我对 Java 字节码有点陌生,所以我可能在这里犯了一个错误。这是程序的输出,它显示 println() 被执行,但是在第一次 invokevirtual调用之后的某个地方抛出了 StackOverflowError:

this is an instrumented println call
Exception in thread "main" java.lang.StackOverflowError
   at com.foo.SimpleTest.main(SimpleTest.java:17)

什么可能导致此 StackOverflowError?我该如何解决?

4

3 回答 3

1

您的 highResCounter 方法正在调用自身:

public long highResCounter() {
    [...]
    invokevirtual long Perf.$wrapped$highResCounter()

您还有更多代码可以向我们展示以找出原因吗?

于 2011-01-19T02:39:13.723 回答
1

发布的代码中没有错误。问题是由 MAX_STACK 和 MAX_LOCALS 方法属性的无效值引起的,这些属性通常由编译器计算。

我使用的字节码库 ASM 让您有机会自动计算这些值,而我没有利用它。通过将 ASM ClassWriter 构造函数更改为以下内容,我得到了无错误代码:

int flags = ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS;
ClassWriter writer = new ClassWriter(flags);

[1] http://asm.ow2.org/asm33/javadoc/user/org/objectweb/asm/ClassWriter.html#COMPUTE_FRAMES

于 2011-01-27T03:23:59.377 回答
0

显示本机功能,它本身也可能是一个问题。iirc StackOverFlowError 被捕获,因此即使是 JNI C 代码也可能导致它。

于 2011-01-23T14:25:36.043 回答