Eseguire il debug con jdb

D: Come si utilizza efficacemente jdb (incluso nel pacchetto JDK 1.2) per eseguire il debug dei programmi Java?

Ho provato molte volte, ma riesco solo a caricare un file di classe in jdb; Non riesco a eseguirne il debug. Il helpcomando non è molto utile.

A: Fai una domanda interessante. Ad essere onesti, non l'ho mai usato jdb. Ho sempre utilizzato il debugger fornito dal mio ambiente IDE. Quindi, per rispondere alla tua domanda, ho dovuto fare una piccola ricerca per conto mio.

Risulta che Sun considera jdbuna prova di concetto per l'API del debugger Java. L'API Java Debugger ci consente di dare un'occhiata al runtime e di eseguire il debug del nostro codice. L' jdbè solo uno attuazione di un debugger che utilizza l'API. Rispetto ai debugger visivi con cui ho familiarità (sì, immagino di essere un debole), non è il debugger più semplice da usare, sebbene sia simile ad altri debugger da riga di comando, come gdb.

Comunque, alla tua domanda. Prima di tentare di eseguire il debug del codice, assicurati di utilizzare l' -gopzione durante la compilazione delle classi. Questa opzione indica al compilatore di includere le informazioni di debug nel file di classe.

Definiamo una classe inventata per il test:

public class TestMe {private int int_value; private String string_value; public static void main (String [] args) {TestMe testMe = new TestMe (); testMe.setInt_value (1); testMe.setString_value ("test"); int intero = testMe.getInt_value (); String string = testMe.getString_value (); Stringa toString = testMe.toString (); } public TestMe () {} public int getInt_value () {return int_value; } public String getString_value () {return string_value; } public void setInt_value (int value) {int_value = value; } public void setString_value (String value) {string_value = value; } public String toString () {return "String value:" + string_value + "int value:" + int_value; }}

Avvia il debugger:

> jdb TestMe 

Tu dovresti vedere:

> Inizializzazione jdb ...> 0xaa: class 

Diamo un'occhiata ad alcuni comandi di base. Per impostare punti di interruzione, dobbiamo conoscere i numeri di riga oi nomi dei metodi dei punti in cui vorremmo interrompere. Per ottenere un elenco di metodi, utilizzare semplicemente il methodscomando:

> metodi TestMe void main (java.lang.String []) void () int getInt_value () java.lang.String getString_value () void setInt_value (int) void setString_value (java.lang.String) java.lang.String toString ( ) 

L'impostazione di un punto di interruzione è semplice. Usa la seguente sintassi:

fermarsi a .[] 

O:

fermarsi a : 

Dovremmo iniziare il debug all'inizio del metodo principale:

> stop in TestMe.main Breakpoint impostato in javaworld.TestMe.main 

Ora che abbiamo un punto di interruzione, possiamo iniziare l'esecuzione. Per raggiungere il punto di interruzione, usa semplicemente il runcomando:

> run run javaworld.TestMe running ... main [1] Breakpoint hit: javaworld.TestMe.main (TestMe: 10) 

A questo punto, il debugger interrompe l'esecuzione sulla prima riga del metodo principale. Notare che il cursore è cambiato per riflettere il metodo in cui ci troviamo attualmente.

Il listcomando visualizzerà il codice nel punto di interruzione. Una freccia indica il punto in cui il debugger ha interrotto l'esecuzione.

main [1] list 6 private String string_value; 7 8 public static void main (String [] args) 9 {10 => TestMe testMe = new TestMe (); 11 testMe.setInt_value (1); 12 testMe.setString_value ("test"); 13 14 int intero = testMe.getInt_value (); principale [1]

Successivamente, vorremo steppassare alcune righe di codice e vedere cosa è cambiato:

main [1] step main [1] Breakpoint hit: javaworld.TestMe. (TestMe: 20) main [1] locals Argomenti del metodo: Variabili locali: this = Valore stringa: null valore int: 0 main [1] list 16 17 String toString = testMe.toString (); 18} 19 20 => public TestMe () 21 {22} 23 24 public int getInt_value () main [1] step main [1] Breakpoint hit: java.lang.Object. (Object: 27) main [1] list Impossibile trovare Object.java main [1] step main [1] Breakpoint hit: javaworld.TestMe. (TestMe: 22) main [1] list 18} 19 20 public TestMe () 21 {22 =>} 23 24 public int getInt_value () 25 {26 return int_value; main [1] step main [1] Breakpoint hit: javaworld.TestMe.main (TestMe: 10) main [1] list 6 private String string_value; 7 8 public static void main (String [] args) 9 {10 => TestMe testMe = new TestMe (); 11 testMe.setInt_value (1); 12 testMe.setString_value ("test");13 14 int intero = testMe.getInt_value (); main [1] step main [1] Breakpoint hit: javaworld.TestMe.main (TestMe: 11) main [1] list 7 8 public static void main (String [] args) 9 {10 TestMe testMe = new TestMe (); 11 => testMe.setInt_value (1); 12 testMe.setString_value ("test"); 13 14 int intero = testMe.getInt_value (); 15 String string = testMe.getString_value (); main [1] locals Argomenti del metodo: Variabili locali: args = testMe = Valore stringa: null valore int: 0main [1] locals Argomenti del metodo: Variabili locali: args = testMe = Valore stringa: null valore int: 0main [1] locals Argomenti del metodo: Variabili locali: args = testMe = Valore stringa: null valore int: 0

Dopo ciascuno step, ho chiamato il listcomando per vedere dove mi trovavo nel codice. Il valore restituito dal comando elencava il numero di riga, ma in qualche modo non mi aiutava molto.

Come si stepvede, il metodo principale è costruire TestMeun'istanza. Ogni passaggio ci porta attraverso il costruttore e infine torna al metodo principale. Il localscomando elenca tutte le variabili locali visibili nello stack corrente. Vediamo che a questo punto nel metodo principale ci sono solo due variabili locali: argse testMe.

Usando step, possiamo entrare in uno qualsiasi dei metodi per vedere cosa sta succedendo. Quando ci combiniamo stepcon il localscomando possiamo vedere le nostre variabili:

main [1] step main [1] Breakpoint hit: javaworld.TestMe.setInt_value (TestMe: 36) main [1] list 32} 33 34 public void setInt_value (int value) 35 {36 => int_value = value; 37} 38 39 public void setString_value (String value) 40 {main [1] locals Argomenti del metodo: Variabili locali: value = 1 this = String value: null int value: 0

Se facciamo ancora stepuna volta, finiamo nel setInt_value()metodo. Se facciamo stepaltre due volte, il metodo imposterà il int_valuemembro su 1e tornerà. (Per verificare che il metodo abbia impostato il valore, utilizzare il localscomando.)

Naturalmente, quando noi step, non vorremo sempre rintracciare ogni metodo che incontriamo. Alcune chiamate di metodo possono annidarsi molto profondamente. Se fossimo costretti a tracciare un'intera gerarchia, potremmo non finire mai. Fortunatamente, jdbha un modo per eseguire un metodo senza risalire a quel metodo: il nextcomando.

jdbfornisce anche alcuni altri stepcomandi. Il stepicomando esegue l'istruzione corrente. In altre parole, il codice in =>verrà eseguito ma la riga corrente non avanzerà all'istruzione successiva. Puoi chiamare stepiun milione di volte, ma il messaggio =>visualizzato dal listcomando non si sposterà.

jdbfornisce anche il step upcomando. La step upchiamata viene eseguita finché il metodo corrente non torna al chiamante. In poche parole, questo stepper esegue un metodo e nient'altro. Prendi il seguente segmento di codice come esempio:

int intero = testMe.getInt_value (); 

Se questa è la nostra riga corrente e eseguiamo step up, il getInt_value()metodo verrà eseguito. Tuttavia, questo è tutto ciò che accadrà. Il valore restituito non verrà impostato su integer.

jdbci permette anche di impostare più punti di interruzione. Per passare direttamente da un punto di interruzione al successivo, jdbfornisce il contcomando.

Infine, ci sono momenti in cui vogliamo esaminare tutti i membri di un'istanza o di una classe. Fortunatamente, jdbfornisce i comandi dumpe print:

main [1] dump TestMe TestMe = 0xa9: class (javaworld.TestMe) {superclass = 0x2: class (java.lang.Object) loader = (sun.misc.Launcher $ AppClassLoader) 0xaa} main [1] print TestMe TestMe = 0xa9: class (javaworld.TestMe) main [1] dump testMe testMe = (javaworld.TestMe) 0xec {private java.lang.String string_value = test private int int_value = 1} main [1] print testMe testMe = String value: test valore int: 1 

Quando corri dumpo sei printsu una classe, ottieni informazioni sulla classe, che includono informazioni sulla superclasse e sul caricatore. Quando esegui dumpe printsu un'istanza, ottieni informazioni sull'istanza, come i membri di dati e i loro valori correnti.

jdbfornisce anche comandi per scendere e sporcare i thread e gli stack. Tuttavia, questi comandi sono davvero oltre lo scopo di jdbun'introduzione.

Un ultimo punto: potresti chiedere: "Come lo usi efficacemente jdb?" L'efficacia d'uso dipenderà dal tuo livello di comfort con jdb. Al primo utilizzo jdb, il comando più importante è help. Il helpcomando elenca ogni comando e fornisce alcune informazioni di base per aiutarti a iniziare. Una volta che hai helpimparato il comando, ti ritroverai a usare i comandi che impostano i punti di interruzione, insieme a stepe list. Qualsiasi combinazione di questi comandi ti consentirà di iniziare a utilizzare jdb. step, list, step, list... dovrebbe aiutare a individuare rapidamente il codice che sta bombardando su di voi.

Ulteriori informazioni su questo argomento

  • "Java Language Debugging", dal sito web Postech ME

    //mech.postech.ac.kr/Java/java.sun.com/products/JDK/debugging/

  • " jdbThe Java Debugger", da Java Developer's Reference, Mike Cohen, et al. (Sams.net Publishing, 1996)

    //docs.online.bg/PROGRAMMING/JAVA_Developers_Reference/ch15.htm

Questa storia, "Debug with jdb" è stata originariamente pubblicata da JavaWorld.