#java #debugging #breakpoints #jvmti #jdi
#java #отладка #точки останова #jvmti #jdi
Вопрос:
У меня есть мой собственный отладчик JDI, который вызывает toString
метод для некоторых объектов:
com.sun.jdi.ObjectReferenceobject object = ...
ThreadReference threadRef = frameProxy.threadProxy().getThreadReference();
Value value = object.invokeMethod(threadRef, toStringMethod,
Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);
Проблема в том, что даже если внутри метода toString() не установлены точки останова, invokeMethod никогда не завершается, поэтому мой отладчик зависает. Например, это происходит, когда я вызываю это для Double
объекта.
Как я могу прервать выполнение invokeMethod
по прошествии некоторого промежутка времени?
Обновление: я попытался реализовать свой собственный Double
объект и поместить некоторые System.out.println()
инструкции в начало и конец toString()
метода, и казалось, что метод выполняется просто отлично, но по какой-то причине отладчик не получает результат. Возможно, это ошибка в JDI, потому что таких ошибок много, но я не ищу решение для этого, я просто ищу способ прервать выполнение invokeMethod()
, если это занимает слишком много времени.
Update2: Я попробовал то, что предлагал Тьерриб, но я могу вызвать только frameProxy.threadProxy().stop(object);
в потоке менеджера. И поток менеджера заблокирован из-за invokeMethod()
, поэтому он не будет выполнять мою команду. Я пробовал что-то вроде этого:
boolean[] isFinished = new boolean[2];
isFinished[0] = false;
DebuggerManagerThreadImpl managerThread = debugProcess.getManagerThread();
new Thread(() - > {
try {
Thread.sleep(2000);
if (!isFinished[0]) {
System.out.println("Invoked");
managerThread.invokeCommand(new DebuggerCommand() {
@Override
public void action() {
try {
frameProxy.threadProxy().stop(object);
} catch (InvalidTypeException e) {
e.printStackTrace();
}
int threadStatus = frameProxy.threadProxy().status();
switch (threadStatus) {
case ThreadReference.THREAD_STATUS_RUNNING:
System.out.println("The thread is running.");
break;
case ThreadReference.THREAD_STATUS_ZOMBIE:
System.out.println("The thread has been completed.");
break;
case ThreadReference.THREAD_STATUS_WAIT:
System.out.println("The thread is waiting.");
break;
default:
System.out.println("The thread is not running / not waiting / not completed : but what is it doing right now ? (a little programmer joke ;) )");
}
}
@Override
public void commandCancelled() {
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Value value = object.invokeMethod(threadRef, toStringMethod,
Collections.EMPTY_LIST, ObjectReference.INVOKE_SINGLE_THREADED);
isFinished[0] = true;
но frameProxy.threadProxy().stop(object);
никогда не выполняется, потому что DebuggerCommand's
action
метод не вызывается (поток заблокирован).
Также это трассировка стека, когда мой отладчик зависает, и я принудительно останавливаю процесс:
com.sun.jdi.VMDisconnectedException
at com.jetbrains.jdi.TargetVM.waitForReply(TargetVM.java:317)
at com.jetbrains.jdi.VirtualMachineImpl.waitForTargetReply(VirtualMachineImpl.java:1170)
at com.jetbrains.jdi.PacketStream.waitForReply(PacketStream.java:86)
at com.jetbrains.jdi.JDWP$ObjectReference$InvokeMethod.waitForReply(JDWP.java:4840)
at com.jetbrains.jdi.ObjectReferenceImpl.invokeMethod(ObjectReferenceImpl.java:413)
ОБНОВЛЕНИЕ 3: какой поток использовать для вызова метода? В настоящее время я использую frameProxy.threadProxy().getThreadReference();
который большую часть времени работает нормально, но не лучше ли создать отдельный поток только для вызова методов на объектах (в моем отладчике JDI у меня также есть агент инструментирования внутри приложения, поэтому я могу создать отдельный поток только для этого варианта использования (возможно, это предотвратит взаимоблокировки?)).
ОБНОВЛЕНИЕ 4: В настоящее время я использую SUSPEND_ALL
в качестве политики приостановки, было бы лучше использовать SUSPEND_EVENT_THREAD
вместо этого?
Комментарии:
1. Обязательно внимательно прочитайте параграф описания javadoc для метода invokeMethod [ docs.oracle.com/javase/8/docs/jdk/api/jpda/jdi/com/sun/jdi / … ] в нем подробно описаны многие условия, при которых целевая виртуальная машина может столкнуться с взаимоблокировкой.
Ответ №1:
Вы можете использовать интерфейс ThreadReference
с методом void stop(ObjectReference throwable)
. javadoc api сообщает «Останавливает этот поток с помощью асинхронного исключения»..
try {
com.sun.jdi.ObjectReferenceobject object = ...
ThreadReference threadRef = frameProxy.threadProxy().getThreadReference();
frameProxy.threadProxy().stop(object);
int threadStatus = frameProxy.threadProxy().status();
switch(threadStatus) {
case ThreadReference.THREAD_STATUS_RUNNING :
log.info("The thread is running.");
break;
case ThreadReference.THREAD_STATUS_ZOMBIE :
log.info("The thread has been completed.");
break;
case ThreadReference.THREAD_STATUS_WAIT :
log.info("The thread is waiting.");
break;
default :
log.info("The thread is not running / not waiting / not completed : but what is it doing right now ? (a little programmer joke ;) )");
}
} catch (ClassNotLoadedException cnle) {
// log exception, or display a message...
} catch (IncompatibleThreadStateException itse) {
// log exception, or display a message...
} catch (InvalidTypeException ite) {
// log exception, or display a message...
}
Когда вы проверяете состояние своего потока с помощью status
метода, вы можете обнаружить, что значения :
- THREAD_STATUS_UNKNOWN
- THREAD_STATUS_ZOMBIE
- THREAD_STATUS_RUNNING
- THREAD_STATUS_SLEEPING
- THREAD_STATUS_MONITOR
- THREAD_STATUS_WAIT
- THREAD_STATUS_NOT_STARTED
Надеюсь, вы найдете способ сделать то, что вам нужно, с материалом, который я здесь предоставил. Примеры из этого или следующего теста, опубликованного на веб-сайте Элвина Александера, также могут быть полезными.
Комментарии:
1. Спасибо. Не могли бы вы, пожалуйста, взглянуть на мое второе обновление. Я уверен, что я чего-то не хватает.