В: Как ефективно използвате jdb (включен в пакета JDK 1.2) за отстраняване на грешки в Java програми?
Опитвал съм много пъти, но имам успех само в зареждането на файл от клас в jdb
; Не мога да го отстраня. В help
заповедта не е от голяма полза.
О: Задавате интересен въпрос. За да бъда честен, никога не съм използвал jdb
. Винаги съм използвал дебъгера, предоставен от моята среда на IDE. Така че, за да отговоря на въпроса ви, трябваше да направя малко собствено проучване.
Оказва се, че Sun счита jdb
доказателство за концепция за API за отстраняване на грешки в Java. API за отстраняване на грешки Java ни позволява да надникнем в изпълнението и да отстраним грешки в нашия код. Това jdb
е само една реализация на дебъгер, който използва API. В сравнение с визуалните дебъгъри, с които съм запознат (да, предполагам, че съм wimp), това не е най-лесният дебъгер за използване - въпреки че е подобен на други дебъгъри на командния ред, като например gdb
.
Във всеки случай, на вашия въпрос. Преди да се опитате да отстраните грешките на вашия код, не забравяйте да използвате -g
опцията, докато компилирате класовете си. Тази опция казва на компилатора да включва информация за отстраняване на грешки във вашия файл на класа.
Нека дефинираме измислен клас за тестване:
публичен клас TestMe {private int int_value; частен низ string_value; публична статична празнота main (String [] args) {TestMe testMe = new TestMe (); testMe.setInt_value (1); testMe.setString_value ("тест"); int цяло число = testMe.getInt_value (); Низ низ = testMe.getString_value (); String toString = testMe.toString (); } public TestMe () {} public int getInt_value () {return int_value; } публичен низ getString_value () {връщане 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; }}
Стартирайте дебъгера:
> jdb TestMe
Трябва да видиш:
> Инициализиране на jdb ...> 0xaa: клас
Нека да разгледаме някои основни команди. За да зададем точки на прекъсване, трябва да знаем номерата на редовете или имената на методите на местата, където бихме искали да прекъснем. За да получите списък с методи, просто използвайте methods
командата:
> методи 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 ( )
Задаването на точка на прекъсване е лесно. Използвайте следния синтаксис:
спрете. []
Или:
спрете на:
Трябва да започнем отстраняване на грешки в началото на основния метод:
> спиране в TestMe.main Точка на прекъсване, зададена в javaworld.TestMe.main
Сега, когато имаме точка на прекъсване, можем да започнем изпълнението. За да стигнете до точката на прекъсване, просто използвайте run
командата:
> run run javaworld.TestMe running ... main [1] Попадане в точка на прекъсване: javaworld.TestMe.main (TestMe: 10)
В този момент дебъгерът спира изпълнението на първия ред на основния метод. Забележете, че курсорът се е променил, за да отразява метода, в който се намираме в момента.
В list
команда ще покаже кода в точката на прекъсване. Стрелка показва мястото, където дебъгерът е спрял изпълнението.
главен [1] списък 6 частен низ string_value; 7 8 публични статични void main (String [] args) 9 {10 => TestMe testMe = new TestMe (); 11 testMe.setInt_value (1); 12 testMe.setString_value ("тест"); 13 14 int integer = testMe.getInt_value (); главен [1]
След това ще искаме да step
прегледаме няколко реда код и да видим какво се е променило:
main [1] step main [1] Попадане в точка на прекъсване: javaworld.TestMe. (TestMe: 20) main [1] local Аргументи на метода: Локални променливи: this = String value: null int value: 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] Удар на точката на прекъсване: java.lang.Object. (Object: 27) main [1] list Не може да се намери Object.java main [1] step main [1] Удар на точката на прекъсване: 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] стъпка main [1] Попадане в точка на прекъсване: javaworld.TestMe.main (TestMe: 10) main [1] list 6 private String string_value; 7 8 публични статични void main (String [] args) 9 {10 => TestMe testMe = new TestMe (); 11 testMe.setInt_value (1); 12 testMe.setString_value ("тест");13 14 int integer = testMe.getInt_value (); главна [1] стъпка главна [1] Попадане в точка на прекъсване: javaworld.TestMe.main (TestMe: 11) main [1] списък 7 8 публична статична празнота main (String [] args) 9 {10 TestMe testMe = new TestMe (); 11 => testMe.setInt_value (1); 12 testMe.setString_value ("тест"); 13 14 int integer = testMe.getInt_value (); 15 низ низ = testMe.getString_value (); main [1] local Аргументи на метода: Локални променливи: args = testMe = String стойност: null int стойност: 0main [1] local Аргументи на метода: Локални променливи: args = testMe = String стойност: null int стойност: 0main [1] local Аргументи на метода: Локални променливи: args = testMe = String стойност: null int стойност: 0
След всеки step
извиках list
командата, за да видя къде съм в кода. Връщаната стойност от командата изброява номера на реда, но по някакъв начин това наистина не ми помогна особено.
Както ние step
виждаме, че основният метод е конструирането на TestMe
екземпляр. Всяка стъпка ни превежда през конструктора и накрая отново към основния метод. В locals
списъците команда всички на локалните променливи видими в текущия стека. Виждаме, че в този момент в основния метод има само две локални променливи: args
и testMe
.
Като използваме step
, можем да влезем във всеки от методите, за да видим какво се случва. Когато комбинираме step
с locals
командата, можем да видим нашите променливи:
main [1] step main [1] Попадане в точка на прекъсване: 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] local Аргументи на метода: Локални променливи: value = 1 this = String value: null int value: 0
Ако step
още веднъж стигнем до setInt_value()
метода. Ако имаме step
още два пъти, методът ще зададе на int_value
члена 1
и да се върне. (За да проверите дали методът е задал стойността, използвайте locals
командата.)
Разбира се, когато ние step
не винаги ще искаме да проследим всеки метод, който срещаме. Някои извиквания на методи могат да се вложат много дълбоко. Ако бяхме принудени да проследим цяла йерархия, може би никога няма да завършим. За щастие jdb
има начин да изпълни метод без проследяване в този метод: next
командата.
jdb
предоставя и няколко други step
команди. В stepi
заповедта се изпълнява текущата инструкция. С други думи, кодът на =>
волята ще се изпълни, но текущият ред няма да премине към следващата инструкция. Можете да се обадите stepi
милион пъти, но =>
показаното от list
командата няма да се премести.
jdb
също предоставя step up
командата. В step up
поканата се изпълнява, докато сегашният метод се връща в повикващия. Просто казано, този степер изпълнява метод и нищо друго. Вземете за пример следния сегмент на кода:
int цяло число = testMe.getInt_value ();
Ако това е нашата текуща линия и ние изпълним step up
, getInt_value()
методът ще се изпълни. Това обаче е всичко, което ще се случи. Връщаната стойност няма да бъде зададена на integer
.
jdb
също ни позволява да зададем множество точки на прекъсване. За да преминете от една точка на прекъсване директно към следващата, jdb
предоставя cont
командата.
И накрая, има моменти, когато искаме да разгледаме всички членове на екземпляр или клас. За щастие, jdb
осигурява dump
и 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 стойност int: 1
Когато стартирате dump
или print
в клас, получавате информация за класа, която включва информация за суперклас и товарач. Когато стартирате dump
и print
на даден екземпляр, получавате информация за инстанция, като членове на данни и техните текущи стойности.
jdb
също така предоставя команди за сваляне и замърсяване в нишките и стековете. Тези команди обаче наистина са извън обхвата на едно jdb
въведение.
Една последна точка: можете да попитате: "Как ефективно използвате jdb
?" Ефективността на използването ще зависи от нивото на комфорт с jdb
. Когато използвате за първи път jdb
, най-важната команда е help
. В help
списъците командни всяка команда и осигурява основна информация ще ви помогнат да започнете. След като сте help
усвоили командата, ще откриете, че използвате командите, които задават точки на прекъсване, заедно с step
и list
. Всяка комбинация от тези команди ще ви позволи да започнете да използвате jdb
. step
, list
, step
, list
... трябва да ви помогне бързо да намерите код, който е бомбардирането на вас.
Научете повече за тази тема
- „Отстраняване на грешки в Java Java“ от уебсайта на Postech ME
//mech.postech.ac.kr/Java/java.sun.com/products/JDK/debugging/
- "
jdb
Java Debugger", от Справочник за разработчици на Java, Mike Cohen, et al. (Издателство Sams.net, 1996)//docs.online.bg/PROGRAMMING/JAVA_Developers_Reference/ch15.htm
Тази история „Отстраняване на грешки с jdb“ е публикувана първоначално от JavaWorld.