Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否有可能获得JDI';调试对象端的Java当前堆栈帧是什么?_Java_Debugging_Breakpoints_Jvmti_Jdi - Fatal编程技术网

是否有可能获得JDI';调试对象端的Java当前堆栈帧是什么?

是否有可能获得JDI';调试对象端的Java当前堆栈帧是什么?,java,debugging,breakpoints,jvmti,jdi,Java,Debugging,Breakpoints,Jvmti,Jdi,因此,JDI允许我们在debuggee应用程序中设置断点,然后通过JDWP获取当前的StackFrame。据我所知,JVMTI在调试对象端用于通过JDWP将请求的信息发送到JDI 是否可以从调试对象本身获取当前的StackFrame(因此,无需将其发送到调试器…调试对象将成为其自己的调试器) 例如,考虑这个代码: //client code int a = 5; StackFrame frame = ... //list will contain variable "a" List<Lo

因此,
JDI
允许我们在debuggee应用程序中设置断点,然后通过
JDWP
获取当前的
StackFrame
。据我所知,
JVMTI
在调试对象端用于通过
JDWP
将请求的信息发送到
JDI

是否可以从调试对象本身获取当前的
StackFrame
(因此,无需将其发送到调试器…调试对象将成为其自己的调试器)

例如,考虑这个代码:

//client code
int a = 5;
StackFrame frame = ...

//list will contain variable "a"
List<LocalVariable> visibleVariables = frame.visibleVariables();
//客户端代码
INTA=5;
堆栈帧帧=。。。
//列表将包含变量“a”
List visibleVariables=frame.visibleVariables();

这是可能的,有一些陷阱

必须在启动时已为JVM启用调试。要连接到您自己的JVM,您需要使用应用程序知道的预定义端口或附加功能,这要求为最近的JVM显式启用自附加

然后,由于必须挂起要检查的线程,因此执行检查的线程不能是同一个线程。因此,您必须将任务委托给不同的线程

比如说

public static void main(String[] args) throws Exception {
    Object o = null;
    int test = 42;
    String s = "hello";
    Map<String, Object> vars = variables();
    System.out.println(vars);
}
// get the variables in the caller’s frame
static Map<String,Object> variables() throws Exception {
    Thread th = Thread.currentThread();
    String oldName = th.getName(), tmpName = UUID.randomUUID().toString();
    th.setName(tmpName);
    long depth = StackWalker.getInstance(
        StackWalker.Option.SHOW_HIDDEN_FRAMES).walk(Stream::count) - 1;

    ExecutorService es = Executors.newSingleThreadExecutor();
    try {
        return es.<Map<String,Object>>submit(() -> {
            VirtualMachineManager m = Bootstrap.virtualMachineManager();
            for(var ac: m.attachingConnectors()) {
                Map<String, Connector.Argument> arg = ac.defaultArguments();
                Connector.Argument a = arg.get("pid");
                if(a == null) continue;
                a.setValue(String.valueOf(ProcessHandle.current().pid()));
                VirtualMachine vm = ac.attach(arg);
                return getVariableValues(vm, tmpName, depth);
            }
            return Map.of();
        }).get();
    } finally {
        th.setName(oldName);
        es.shutdown();
    }
}

private static Map<String,Object> getVariableValues(
        VirtualMachine vm, String tmpName, long depth)
        throws IncompatibleThreadStateException, AbsentInformationException {

    for(ThreadReference r: vm.allThreads()) {
        if(!r.name().equals(tmpName)) continue;
        r.suspend();
        try {
            StackFrame frame = r.frame((int)(r.frameCount() - depth));
            return frame.getValues(frame.visibleVariables())
                .entrySet().stream().collect(HashMap::new,
                    (m,e) -> m.put(e.getKey().name(), t(e.getValue())), Map::putAll);
        } finally {
            r.resume();
        }
    }
    return Map.of();
}
private static Object t(Value v) {
    if(v == null) return null;
    switch(v.type().signature()) {
        case "Z": return ((PrimitiveValue)v).booleanValue();
        case "B": return ((PrimitiveValue)v).byteValue();
        case "S": return ((PrimitiveValue)v).shortValue();
        case "C": return ((PrimitiveValue)v).charValue();
        case "I": return ((PrimitiveValue)v).intValue();
        case "J": return ((PrimitiveValue)v).longValue();
        case "F": return ((PrimitiveValue)v).floatValue();
        case "D": return ((PrimitiveValue)v).doubleValue();
        case "Ljava/lang/String;": return ((StringReference)v).value();
    }
    if(v instanceof ArrayReference)
        return ((ArrayReference)v).getValues().stream().map(e -> t(e)).toArray();
    return v.type().name()+'@'+Integer.toHexString(v.hashCode());
}

这会比从外部JVM连接更快吗?对我来说,最重要的是以一种非常快的方式实现这一点(不需要VM停止或通过套接字进行通信)…我不这么认为。开发人员没有预见到应用程序调试本身,因此他们肯定没有针对这种情况实施任何优化。在我看来,使用attachapi只会消除事先知道端口号的需要,但最终会使用套接字通信。如果您的任务像问题中描述的那样狭窄(获取您自己的当前堆栈帧),那么字节码插装将允许更快的解决方案,而根本不需要JVM的调试功能。