2017-06-26 2 views
2

Verwenden von Argumenten -Xdebug, -agentlib: jdwp = Transport = dt_socket, Server = y, Aussetzung = n, Adresse = 4404 Zielprogramm starten.Debuggen einer Klasse, die von einem benutzerdefinierten Klassenlader in JDI geladen wurde

Debuggen Sie das Zielprogramm mit der verwandten Klasse com.sun.jdi. Die classesByName-Methode der VirtualMachine-Klasse. Die Klasse, die vom benutzerdefinierten Klassenladeprogramm geladen wird, ist nicht verfügbar.

in Ziel kann ich Klasse von

Class.forName("Script1", false, clazz.getClassLoader()) 

in Klasse Virtuelle Maschine bekommen, hat nur Methode:

List<ReferenceType> classesByName(String var1); 

Wie soll ich tun?

+0

Meinst du "Die Klasse, die von der benutzerdefinierten Klasse geladen wird, ist nicht verfügbar."? –

+0

Ja, ich kann keinen Breakpoint auf einer 'GroovyClass' setzen, die von grovvy classloader geladen wird, pure java klasse kein solches Problem – Channe

+0

Es gibt eine Option, um den Klassenpfad des entfernten Debuggens zu optimieren. Ich bin mir ziemlich sicher, dass das der kleine Tweak in Ihrer Debug-Konfiguration ist, der fehlt. –

Antwort

1

Überwachung Classloading in JDI In den letzten Wochen habe ich ein Java-Prozess-Monitoring-Tool auf der Grundlage der Java Debug Interface erstellt. Obwohl ich schon viel von dieser Arbeit gemacht habe, sind es schon ein paar Jahre vergangen, und jetzt ziehe ich meine Schritte zurück. Wenn ich mich an die Details und Fallstricke erinnere, habe ich meine Notizen in der Hoffnung gepostet, dass Sie sie nützlich finden.

Heute werde ich nach ein wenig Hintergrund über ClassPrepareEvents sprechen. Wie Sie wahrscheinlich bereits wissen, können Sie einen Debugger an einen bereits laufenden Java-Prozess anhängen oder den Zielprozess selbst über Ihren Debugger starten (mithilfe verschiedener Befehlszeilenoptionen). In meinem Projekt werde ich mich immer an einen laufenden Prozess halten, da es darum geht, Prozessdaten nach Bedarf zu sammeln. Der Grund dafür, dass JDs ClassPrepareEvent interessant ist, ist, dass beim Starten eines Debug-Zielprozesses oder sogar beim Anhängen an einen bereits laufenden Prozess einige der gewünschten Breakpoints wahrscheinlich in Klassen liegen, die noch nicht geladen wurden.

In meinem üblichen Szenario rufe ich die allClasses() -Methode der com.sun.jdi.VirtualMachine auf, um eine Liste aller geladenen ReferenceTypes zu erhalten. Eine Möglichkeit, sich einen ReferenceType vorzustellen, ist ein Teil einer Java-Klassendefinition. Wenn Ihre Java-Klasse innere Klassen hat, werden sie von JDI in separate ReferenceTypes aufgeteilt. Jeder ReferenceType enthält eine Sammlung von Zeilenpositionen. diese entsprechen Codezeilen, auf denen Breakpoints gesetzt werden können und die unter anderem durch die Quellcodezeilennummer identifiziert werden. Wenn eine Zeile des Quellcodes nicht das Ziel eines Haltepunkts sein kann, wird im ReferenceType keine Zeilenposition für den Haltepunkt angezeigt. In meinen Debugger-basierten Anwendungen durchlaufe ich die Zeilenpositionen aller ReferenceTypes, passe Zeilenpositionen mit Haltepunktspezifikationen ab und registriere dann meine Haltepunktanforderungen.

Wie Sie sich denken können, habe ich ein potenzielles Problem: Was soll ich tun, wenn eine Klasse, die ich brauche, zum Zeitpunkt der Erstellung meiner Haltepunktanforderungen noch nicht geladen wurde? Die Antwort ist: JDs ClassPrepareEvent. Der Einstiegspunkt für die Verwendung dieses Teils der API ist die createClassPrepareRequest() -Methode des EventRequestManagers. Nachdem wir unsere Anfrage gestellt haben, kann die gleiche Ereignis-Listener-Schleife, die wir auf Haltepunkt-Ereignisse warten, auch dazu verwendet werden, auf Klassenvorbereitungs-Ereignisse zu warten (siehe die JVM-Spezifikation für eine Definition der Klassenvorbereitung).

Eine Sache, die ich aus meiner früheren Entwicklung auf dieser API erinnere, ist, dass hier ein Timing-Risiko besteht. Wahrscheinlich möchten Sie die Klassenvorbereitungsanforderung erstellen, bevor Sie über die Liste der aktuell geladenen Klassen iterieren. Der Grund ist, dass Sie nicht in diese Falle fallen wollen: Iterate über eine Reihe der aktuell geladenen Klassen, Verarbeitung und Erstellung von Breakpoint-Anfragen. Plötzlich ist eine Klasse geladen, die Sie brauchen! Sie registrieren Ihr Class-Prepare-Ereignis und beginnen, Ereignisse zu erhalten, wenn Klassen geladen werden, aber Sie verpassen die Klasse, die zwischen Schritt 1 und Schritt 3 geladen wurde. Hier ist eine weitere mögliche Falle: Registrieren Sie sich für Ereignisse zur Vorbereitung auf Ereignisse, damit Sie nicht von dem obigen Problem betroffen sind. Iterieren Sie über die aktuell geladenen Klassen und fordern Sie ggf. Haltepunkte an. Verarbeiten Sie neu geladene Klassen und fordern Sie bei Bedarf Haltepunkte an. Das Problem mit diesem zweiten Ansatz besteht darin, dass Sie den gleichen Haltepunkt zweimal verarbeiten können. Warum? Zu dem Zeitpunkt, an dem Sie über die aktuell geladenen Klassen iterieren, werden einige der Klassen in dieser Liste höchstwahrscheinlich Klassen sein, die in Ihrem Klassenvorbereitungs-Listener aufgetaucht sind. Keines dieser Probleme kann behoben werden, indem irgendwo ein synchronisiertes Schlüsselwort geklickt wird.

Unabhängig davon, ob Sie Ihre Zielanwendung von Ihrem Debugger aus starten oder nachträglich anhängen, müssen Sie sich mit einigen Variationen dieses Problems befassen. Die Art, wie ich damit umgehe, besteht darin, der Klasse, die ich zum Definieren jeder Haltepunktspezifikation verwende, einen Zustand hinzuzufügen. Wenn jede entsprechende geladene Klasse gefunden und die Haltepunktanforderung ausgeführt wird, setze ich ein Flag für die Spezifikation, so dass ich weiß, dass die Anforderung registriert wurde. Außerdem folge ich dem zweiten oben beschriebenen Ansatz (besser Duplikate zu haben, als einen zu verpassen). Wenn ich ein Class-Prepare-Ereignis für eine Klasse sehe, die ich bereits aus der ReferenceType-Liste der VM verarbeitet habe, überspringe ich es einfach. Ich mache das gleiche für die umgekehrte Situation, in der meine Liste von ReferenceTypes ReferenceTypes enthält, die ich gerade in meinem ClassPrepareEvent-Listener verarbeitet habe.

Schließlich habe ich noch nie ein Problem (entweder für diesen Entwicklungsaufwand oder in meiner früheren Entwicklung in diesem Bereich) untersucht - was passiert, wenn eine Klasse entladen wird, insbesondere eine Klasse, für die Sie Haltepunktanforderungen registriert haben . Wird beispielsweise eine registrierte Haltepunktanforderung verhindern, dass eine Klasse entladen wird? Interessiert Sie eine gestrandete Haltepunktanforderung, wenn die Klasse nicht einmal geladen ist? (Antwort: Ja, nehme ich an, wenn es neu geladen wird und Sie keine gültige Haltepunktanforderung mehr haben). JDI verfügt über ein ClassUnloadEvent, für das Sie ebenfalls einen Listener registrieren können. Wie gesagt, ich habe mich mit diesem (möglichen) Problem nicht befasst, da ich nie gesehen habe, dass eine Zielklasse zuvor entladen wurde, aber es ist gut zu wissen, "es gibt eine API dafür". Follow link for more details

+0

sehr hilfreich, danke. – Channe

Verwandte Themen