저는 자바, 특히 메모리 관리와 스레드에 대해 더 많이 이해하려고합니다. 이런 이유로 최근에 스레드 덤프에 관심이 있습니다.
다음은 Java 용 기본 제공 도구 인 VisualVM을 사용하는 웹 앱에서 가져온 몇 줄입니다.
"Finalizer" daemon prio=8 tid=0x02b3d000 nid=0x898 in Object.wait() [0x02d0f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
- locked <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
Locked ownable synchronizers:
- None
"Reference Handler" daemon prio=10 tid=0x02b3b800 nid=0x494 in Object.wait() [0x02cbf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x27ef0310> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:485)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x27ef0310> (a java.lang.ref.Reference$Lock)
먼저 몇 가지 변수 이름에 대한 질문이 있습니다.
- tid and nid은 무슨 뜻인가요?
- Object.wait 다음에 제곱 괄호 안의 숫자는 무엇입니까?
그런 다음 스택 추적 자체의 경우 :
- <…..> (java.lang ….)을 기다리는 것은 무엇을 의미 하며 <..> 의 숫자는 무엇입니까?
- 잠긴 <…..> (java.lang ….) 같은 질문, <..>에 있는 것은 무엇을 의미합니까?
잠긴 단어가 왠지 대기 조건과 관련이 있다고 생각했지만 틀 렸습니다. 실제로 locked가 세 번 반복되는 이유가 궁금하지만 스레드는 동일한 덤프에서 볼 수 있듯이 실행 가능한 상태입니다.
"Thread-0" prio=6 tid=0x02ee3800 nid=0xc1c runnable [0x03eaf000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:199)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
- locked <0x23963378> (a java.io.BufferedInputStream)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
- locked <0x23968450> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
- locked <0x23968450> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at org.codehaus.plexus.util.cli.StreamPumper.run(StreamPumper.java:145)
마지막으로, 이것은 그들 중 최악이었습니다.
"CompilerThread0" daemon prio=10 tid=0x02b81000 nid=0x698 waiting on condition [0x00000000]
java.lang.Thread.State: RUNNABLE
이 스레드는 실행 가능한 상태이지만 조건에 따라 대기 중입니다. 어떤 조건과 0x00000은 무엇입니까?
스레드 클래스의 증거없이 스택 추적이 너무 짧은 이유는 무엇입니까?
제 모든 질문에 답해 주시면 매우 감사하겠습니다.
감사
답변
TID는 thead id이고 NID는 네이티브 스레드 ID입니다. 이 ID는 플랫폼에 따라 다릅니다. jstack 스레드 덤프의 NID입니다. Windows에서는 단순히 프로세스 내의 OS 수준 스레드 ID입니다. Linux 및 Solaris에서는 스레드의 PID (경량 프로세스)입니다. Mac OS X에서는 기본 pthread_t 값이라고합니다.
이 두 용어에 대한 정의 및 추가 설명을 보려면 다음 링크로 이동하십시오. Java 수준 스레드 ID :
IBM 사이트에서 다음 링크를 찾았습니다 . 스레드 덤프 해석 방법 . 이를 더 자세히 다룹니다.
대기가 의미하는 바를 설명합니다. 잠금은 둘 이상의 엔티티가 공유 리소스에 액세스하는 것을 방지합니다. Java ™의 각 오브젝트에는 연관된 잠금이 있습니다 (동기화 된 블록 또는 메소드를 사용하여 확보됨). JVM의 경우 스레드는 JVM의 다양한 리소스에 대해 경쟁하고 Java 개체를 잠급니다.
그런 다음 스레드 간의 유연한 동기화를 허용하기 위해 JVM에서 사용되는 특수한 잠금 메커니즘으로 모니터를 설명합니다. 이 섹션의 목적을 위해 모니터 및 잠금이라는 용어를 같은 의미로 읽으십시오.
그런 다음 더 나아갑니다.
모든 개체에 대한 모니터를 방지하기 위해 JVM은 일반적으로 클래스 또는 메서드 블록의 플래그를 사용하여 항목이 잠겨 있음을 나타냅니다. 대부분의 경우 코드는 경합없이 일부 잠긴 섹션을 통과합니다. 따라서 가디언 플래그는이 코드 조각을 보호하기에 충분합니다. 이를 평면 모니터라고합니다. 그러나 다른 스레드가 잠긴 일부 코드에 액세스하려는 경우 진정한 경합이 발생했습니다. JVM은 이제 두 번째 스레드를 보유하고 코드 섹션에 대한 액세스를 조정하기위한 신호 메커니즘을 배열하기 위해 모니터 오브젝트를 작성 (또는 확장)해야합니다. 이 모니터는 이제 부풀린 모니터라고합니다.
다음은 스레드 덤프의 줄에 표시되는 내용에 대한 자세한 설명입니다. Java 스레드는 운영 체제의 기본 스레드에 의해 구현됩니다. 각 스레드는 다음과 같이 굵은 선으로 표시됩니다.
“Thread-1″(TID : 0x9017A0, sys_thread_t : 0x23EAC8, state : R, 기본 ID : 0x6E4) prio = 5
* 다음 6 개 항목은 괄호 [] 안의 값을 예제에서 비교 했으므로이를 설명합니다.
- 이름 [ Thread-1 ],
- 식별자 [ 0x9017A0 ],
- JVM 데이터 구조 주소 [ 0x23EAC8 ],
- 현재 상태 [ R ],
- 원시 스레드 식별자 [ 0x6E4 ],
- 우선 순위 [ 5 ].
“wait on”은 응용 프로그램 스레드 perse가 아니라 jvm 자체와 관련된 데몬 스레드로 나타납니다. “in Object.wait ()”를 받으면 데몬 스레드 인 “finalizer”가 객체의 잠금에 대한 알림을 기다리고 있음을 의미합니다.이 경우에는 어떤 알림을 기다리고 있는지 보여줍니다. “- <0x27ef0288> (java.lang.ref.ReferenceQueue $ Lock)에서 대기 “
ReferenceQueue의 정의는 다음과 같습니다. 적절한 도달 가능성 변경이 감지 된 후 가비지 수집기가 등록 된 참조 개체를 추가하는 참조 대기열입니다.
종료 자 스레드가 실행되어 가비지 컬렉션이 개체와 관련된 리소스를 정리하도록 작동합니다. 핵심적으로 보면 종료자는이 객체에 대한 잠금을 얻을 수 없습니다. java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:118) Java 객체가 메서드를 실행 중이므로 종료 자 스레드는 다음과 같습니다. 해당 개체가 현재 작업으로 완료 될 때까지 잠 깁니다.
또한 종료자는 단순히 메모리를 회수하는 것이 아니라 리소스를 정리하는 것보다 더 많이 관련됩니다. 더 많은 연구가 필요하지만 객체 메서드와 관련된 파일이 열려 있고 소켓 등이 있으면 종료자가 해당 항목을 해제하는 작업도 수행합니다.
스레드 덤프에서 Object.wait 뒤의 제곱 괄호 안의 숫자는 무엇입니까?
스레드에 대한 메모리의 포인터입니다. 다음은 더 자세한 설명입니다.
C.4.1 스레드 정보
스레드 섹션의 첫 번째 부분은 다음과 같이 치명적인 오류를 유발 한 스레드를 보여줍니다.
Current thread (0x0805ac88): JavaThread "main" [_thread_in_native, id=21139]
| | | | +-- ID
| | | +------------- state
| | +-------------------------- name
| +------------------------------------ type
+-------------------------------------------------- pointer
스레드 포인터는 Java VM 내부 스레드 구조에 대한 포인터입니다. 라이브 Java VM 또는 코어 파일을 디버깅하지 않는 한 일반적으로 관심이 없습니다.
이 마지막 설명의 출처 : HotSpot VM이있는 Java SE 6 문제 해결 가이드
스레드 덤프에 대한 몇 가지 추가 링크는 다음과 같습니다.
- 스레드 작동 방식
- 스레드 덤프를 분석하는 방법
- 자바 스레드 덤프
- 자바 VM 스레드
- Stackoverflow 질문 : 스레드가 매핑되는 방법
답변
@James Drinkard의 훌륭한 답변에 더해 :
기본 구현에 따라 원시 메소드에서 차단 된 스레드 의 java.lang.Thread.State가로 보고 될 수 있습니다 RUNNABLE
. 여기서A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.
이 설명은 폴 또는 읽기 작업과 같은 OS 호출에서 차단되는 것도 포함하는 것으로 밝혀졌습니다. 아마도 JVM이 OS 수준에서 네이티브 메서드 호출이 차단 된시기를 알 수 있다는 보장이 없기 때문일 것입니다.
내가 본 JVM 스레드 덤프에 대한 많은 논의는이 가능성을 완전히 무시하거나 의미를 고려하지 않고 가볍게 훑어 보는 중입니다. 모두 100 %로 실행됩니다.