1. 개요
원격 Java 응용 프로그램을 디버깅하는 것은 여러 경우에 유용할 수 있습니다.
이 사용방법(예제)에서는 JDK의 도구를 사용하여 이를 수행하는 방법을 알아봅니다.
2. 신청
신청서 작성부터 시작하겠습니다. 원격 위치에서 실행하고 이 문서를 통해 로컬에서 디버그합니다.
public class OurApplication {
private static String staticString = "Static String";
private String instanceString;
public static void main(String[] args) {
for (int i = 0; i < 1_000_000_000; i++) {
OurApplication app = new OurApplication(i);
System.out.println(app.instanceString);
}
}
public OurApplication(int index) {
this.instanceString = buildInstanceString(index);
}
public String buildInstanceString(int number) {
return number + ". Instance String !";
}
}
그런 다음 모든 디버깅 정보를 포함하도록 -g 플래그로 컴파일합니다.
javac -g OurApplication.java
3. JDWP: 자바 디버그 유선 프로토콜
Java Debug Wire Protocol 은 디버 기와 디버거 간의 통신을 위해 Java에서 사용되는 프로토콜입니다 . 디버기는 디버깅 중인 응용 프로그램이고 디버거는 응용 프로그램이거나 디버깅 중인 응용 프로그램에 연결하는 프로세스입니다.
두 응용 프로그램 모두 동일한 시스템 또는 다른 시스템에서 실행됩니다. 우리는 후자에 초점을 맞출 것입니다.
3.1. JDWP의 옵션
디버기 응용 프로그램을 시작할 때 JVM 명령줄 인수에서 JDWP를 사용합니다.
호출에는 옵션 List이 필요합니다.
- transport 는 완전히 필요한 유일한 옵션입니다. 사용할 전송 메커니즘을 정의합니다. dt_shmem 은 Windows에서만 작동 하며 dt_socket 은 모든 플랫폼과 호환되는 반면 두 프로세스가 동일한 시스템에서 실행되는 경우 프로세스가 다른 시스템에서 실행될 수 있습니다.
- 서버 는 필수 옵션이 아닙니다. 이 플래그가 켜져 있으면 디버거에 연결하는 방식을 정의합니다. 주소 옵션 에 정의된 주소를 통해 프로세스를 노출합니다 . 그렇지 않으면 JDWP가 기본 항목을 노출합니다.
- suspend 는 JVM을 일시 중단하고 디버거가 연결될 때까지 기다려야 하는지 여부를 정의합니다.
- address 는 디버기에 의해 노출되는 주소(일반적으로 포트)를 포함하는 옵션입니다. 또한 문자열로 변환된 주소를 나타낼 수도 있습니다(예 : Windows 에서 주소 를 제공하지 않고 server=y 를 사용하는 경우 javadebug ).
3.2. 시작 명령
원격 애플리케이션을 시작하여 시작하겠습니다. 이전에 나열된 모든 옵션을 제공합니다.
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 OurApplication
Java 5까지는 JVM 인수 runjdwp 를 다른 옵션 debug 와 함께 사용해야 했습니다 .
java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
이러한 JDWP 사용 방법은 계속 지원되지만 향후 릴리스에서는 삭제될 예정입니다. 가능하면 최신 표기법을 사용하는 것이 좋습니다.
3.3. 자바 9부터
마지막으로 JDWP 옵션 중 하나가 Java 버전 9 릴리스와 함께 변경되었습니다. 이것은 하나의 옵션에만 관련되기 때문에 아주 사소한 변경이지만 원격 애플리케이션을 디버깅하려는 경우 차이를 만들 것입니다.
이 변경 사항은 주소 가 원격 애플리케이션에 대해 작동 하는 방식에 영향을 줍니다 . 이전 표기법 address=8000 은 localhost 에만 적용됩니다 . 이전 동작을 달성하기 위해 콜론과 함께 별표를 주소의 접두사로 사용합니다(예: address=*:8000 ).
설명서에 따르면 이것은 안전하지 않으며 가능할 때마다 디버거의 IP 주소를 지정하는 것이 좋습니다.
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:8000
4. JDB: 자바 디버거
Java 디버거인 JDB는 명령줄에서 편리한 디버거 클라이언트를 제공하기 위해 고안된 JDK에 포함된 도구입니다.
JDB를 시작하기 위해 연결 모드를 사용합니다. 이 모드는 JDB를 실행 중인 JVM에 연결합니다. 수신 또는 실행 과 같은 다른 실행 모드가 있지만 로컬에서 실행 중인 애플리케이션을 디버깅할 때 대부분 편리합니다.
jdb -attach 127.0.0.1:8000
> Initializing jdb ...
4.1. 중단점
섹션 1에 제시된 응용 프로그램에 몇 가지 중단점을 설정하여 계속하겠습니다.
생성자에 중단점을 설정합니다.
> stop in OurApplication.<init>
String 클래스 의 정규화된 이름을 사용하여 정적 메서드 main 에서 또 다른 것을 설정합니다.
> stop in OurApplication.main(java.lang.String[])
마지막으로 인스턴스 메서드 buildInstanceString 에 마지막 항목을 설정합니다 .
> stop in OurApplication.buildInstanceString(int)
이제 서버 애플리케이션이 중지되고 디버거 콘솔에 다음이 출력되는 것을 확인할 수 있습니다.
> Breakpoint hit: "thread=main", OurApplication.<init>(), line=11 bci=0
이제 app.instanceString 변수 가 인쇄 되는 특정 줄에 중단점을 추가해 보겠습니다 .
> stop at OurApplication:7
중단점이 특정 줄에 정의되어 있을 때 in 대신 stop 다음에 at 이 사용 된다는 것을 알 수 있습니다.
4.2. 탐색 및 평가
이제 중단점을 설정했으므로 cont 를 사용 하여 7행의 중단점에 도달할 때까지 스레드를 계속 실행해 보겠습니다.
콘솔에 다음이 인쇄되는 것을 볼 수 있습니다.
> Breakpoint hit: "thread=main", OurApplication.main(), line=7 bci=17
다음 코드가 포함된 줄에서 멈췄습니다.
System.out.println(app.instanceString);
이 행에서 중지하는 것은 기본 메서드에서 중지하고 step 을 두 번 입력하여 수행할 수도 있습니다. 단계 는 현재 코드 줄을 실행하고 다음 줄에서 직접 디버거를 중지합니다.
이제 중지했으므로 디버거는 staticString , 앱 의 instanceString , 로컬 변수 i 를 평가하고 마지막으로 다른 표현식을 평가하는 방법을 살펴봅니다.
staticField 를 콘솔에 출력해 봅시다 :
> eval OurApplication.staticString
OurApplication.staticString = "Static String"
정적 필드 앞에 클래스 이름을 명시적으로 입력합니다.
이제 app 의 인스턴스 필드를 인쇄해 보겠습니다 .
> eval app.instanceString
app.instanceString = "68741. Instance String !"
다음으로 변수 i 를 살펴보겠습니다 .
> print i
i = 68741
다른 변수와 달리 지역 변수는 클래스나 인스턴스를 지정할 필요가 없습니다. 또한 print 가 eval 과 정확히 동일한 동작을 한다는 것을 알 수 있습니다 . 둘 다 표현식이나 변수를 평가합니다.
정수를 생성자 매개변수로 전달한 OurApplication 의 새 인스턴스를 평가합니다 .
> print new OurApplication(10).instanceString
new OurApplication(10).instanceString = "10. Instance String !"
이제 필요한 모든 변수를 평가했으므로 이전에 설정한 중단점을 삭제하고 스레드가 처리를 계속하도록 할 것입니다. 이를 달성하기 위해 clear 명령 뒤에 중단점 식별자를 사용합니다.
식별자는 이전에 stop 명령과 함께 사용한 것과 정확히 동일합니다 .
> clear OurApplication:7
Removed: breakpoint OurApplication:7
중단점이 올바르게 제거되었는지 확인하기 위해 인수 없이 clear 를 사용합니다. 그러면 방금 삭제한 것이 없는 기존 중단점 List이 표시됩니다.
> clear
Breakpoints set:
breakpoint OurApplication.<init>
breakpoint OurApplication.buildInstanceString(int)
breakpoint OurApplication.main(java.lang.String[])
5. 결론
이 빠른 기사에서는 JDK 도구인 JDB와 함께 JDWP를 사용하는 방법을 발견했습니다.
물론 도구에 대한 자세한 내용은 각각 의 참조인 JDWP 및 JDB에서 찾을 수 있습니다 .