从JVM获取正在运行的字节码

时间:2015-08-20 19:49:20

标签: java jvm

我试图找出在将函数加载到JVM之后是否可以获取函数的字节码。

我知道我可以使用ClassLoder从.class文件中获取代码,我可以使用Instrumentation来操作它,但这不是问题所在。

假设我有一个名为Test.class的编译Java程序并且我运行,它的字节码将被加载到JVM中,从这一点我可以得到字节码吗?

编辑: 根据我想再次指出的答案,我的目的是检查在JVM上运行的代码,但我无权访问其编译文件。

2 个答案:

答案 0 :(得分:1)

如果没有更多的背景,我不确定你要做什么,但是:

如果您只是想查看类文件(字节码和所有内容)的内容,那么javap -c Test.class会为您吐出来。

如果您想在JVM运行时看到代码的样子,agent可能就是您要找的。

请记住,如果你的函数(方法?我假设我们在这里不讨论lambdas)依赖于父作用域中的任何变量,那么所述方法的字节码就不能描述它自己的作用。想想内部类,lambdas,e.t.c。

修改

正如Peter Lawrey所说,如果你想放弃代理,将类加载器中的原始字节提供给ASM的访问者API是一个好的开始。 ASM doc有一个教程;谷歌也出现了this(见第2部分)。 HTH

答案 1 :(得分:1)

HotSpot Serviceability Agent可以做到这一点!

以下是如何在main(String[])类中获取远程test.HelloWorld方法的字节码的示例:

import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Method;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;

public class GetBytecode extends Tool {

    @Override
    public void run() {
        VM.getVM().getSystemDictionary().allClassesDo(klass -> {
            if (klass.getName().asString().equals("test/HelloWorld")) {
                Method method = ((InstanceKlass) klass).findMethod("main", "([Ljava/lang/String;)V");
                for (byte bc : method.getByteCode()) {
                    System.out.printf("%02x ", bc);
                }
            }
        });
    }

    public static void main(String[] args) {
        new GetBytecode().execute(args);
    }
}

运行java -cp <JDK_HOME>/lib/sa-jdi.jar:. GetBytecode <PID>