이 글에서는 JVM 스레드 스택을 분석하는 방법과 스택 정보에서 문제의 근본 원인을 찾는 방법을 알려드리겠습니다. 내 생각에 스레드 스택 분석 기술은 Java EE 제품 지원 엔지니어가 마스터해야 할 기술이다. 스레드 스택에 저장된 정보는 일반적으로 상상을 훨씬 뛰어넘으며, 우리는 이 정보를 작업에 잘 활용할 수 있습니다.
지난 12년간 스레드 분석에서 축적한 지식과 경험을 공유하는 것이 나의 목표입니다. 이러한 지식과 경험은 다양한 버전의 JVM 및 다양한 벤더의 JVM 벤더에 대한 심층 분석을 통해 얻은 것입니다. 그 과정에서 저는 또한 다수의 공통적인 문제 템플릿을 요약했습니다.
그럼 준비되셨나요? 지금 이 기사를 북마크에 추가하세요. 다음 주에 이 특별 기사 시리즈를 전해 드리겠습니다. 무엇을 기다리고 계십니까? 이 스레드 분석 교육 계획을 동료 및 친구들과 공유하십시오.
좋네요. 스레드 스택 분석 기술을 확실히 향상시켜야 하는데... 어디서부터 시작해야 할까요?
제 제안은 이 스레드 분석 교육 프로그램을 따라가는 것입니다. 아래는 우리가 다룰 교육 내용입니다. 동시에 제가 처리한 실제 사례를 여러분과 공유하여 여러분이 배우고 이해할 수 있도록 하겠습니다.
1) 스레드 스택 개요 및 기본 지식
2) 스레드 스택 생성 원리 및 관련 도구
3) 다양한 JVM(Sun HotSpot, IBM JRE, Oracal)의 스레드 스택 형식 차이 JRockit)
4) 스레드 스택 로그 소개 및 분석 방법
5) 스레드 스택 분석 및 관련 기술
6) 공통 문제 템플릿(스레드 경합, 교착 상태, IO 호출 중단, 가비지 수집/OutOfMemoryError 문제, 무한 루프 등)
7) 스레드 스택 문제 분석 예시
이 일련의 교육이 여러분에게 실질적인 도움이 되기를 바랍니다. 계속해서 주간 기사 업데이트에 관심을 가져주시기 바랍니다.
그런데 학습 과정에서 궁금한 점이 있거나 기사 내용을 이해할 수 없으면 어떻게 해야 하나요?
걱정하지 마시고 저를 멘토라고 생각해주세요. 스레드 스택에 대해 궁금한 점이 있으면 저에게 상담해 주세요(문제가 너무 낮지 않은 경우). 저에게 연락하시려면 다음 방법 중 하나를 선택해 주시기 바랍니다.
1) 이 기사 바로 아래에 댓글을 남겨주세요. (죄송한 경우 익명으로 유지하실 수 있습니다.)
2) 귀하의 의견을 제출해 주세요. 근본 원인 분석 포럼에 스레드 스택 데이터
3) @phcharbonneau@hotmail.com으로 이메일을 보내주십시오.
저희 제품에서 발생한 문제를 분석하는 데 도움을 주실 수 있나요?
물론, 원한다면 이메일이나 근본 원인 분석 포럼을 통해 스택 라이브 데이터를 나에게 보낼 수 있습니다. 실질적인 문제를 다루는 것은 기술을 배우고 향상시키는 가장 좋은 방법입니다.
이번 교육이 마음에 드셨으면 좋겠습니다. 그래서 최선을 다해 질 높은 자료를 제공하고, 여러분의 질문에 답변해 드리겠습니다.
스레드 스택 분석 기술과 문제 패턴을 소개하기에 앞서, 기본적인 내용을 먼저 말씀드리고 싶습니다. 그래서 이번 포스팅에서는 모든 분들이 JVM, 미들웨어, Java EE 컨테이너 간의 상호작용을 더 잘 이해할 수 있도록 가장 기본적인 내용부터 다루겠습니다.
Java VM 개요
Java Virtual Machine은 Java EE 플랫폼의 기반입니다. 미들웨어와 애플리케이션이 배포되고 실행되는 곳입니다.
JVM은 미들웨어 소프트웨어와 Java/Java EE 프로그램에 다음을 제공합니다.
– (바이너리 형식) Java/Java EE 프로그램 실행 환경
– 일부 프로그램 기능 및 도구 (IO 인프라, 데이터 구조, 스레드 관리, 보안, 모니터링 등)
– 가비지 수집을 통한 동적 메모리 할당 및 관리
JVM은 운영 체제(Solaris, AIX, Windows 등), 물리적 서버 구성에 따라 각 물리적/가상 서버에 1~여러 개의 JVM 프로세스를 설치할 수 있습니다.
JVM과 미들웨어 간 상호 작용
다음은 다음과 같습니다. 그림은 JVM, 미들웨어 및 애플리케이션 간의 고급 상호 작용 모델을 보여줍니다.
그림은 JVM, 미들웨어 및 애플리케이션 소프트웨어 간의 간단하고 일반적인 상호 작용을 보여줍니다. 보시다시피 표준 Java EE 애플리케이션에 대한 스레드 할당은 미들웨어 커널과 JVM 사이에서 수행됩니다. (물론 예외도 있습니다. 애플리케이션이 API를 직접 호출하여 스레드를 생성할 수 있습니다. 이는 일반적이지 않으며 사용 시 특별한 주의가 필요합니다)
동시에 내부적으로 일부 스레드가 생성되는 점 참고하시기 바랍니다 관리를 위해 일반적인 예로는 JVM이 병렬 가비지 수집 처리를 수행하기 위해 내부적으로 사용하는 가비지 수집 스레드가 있습니다.
대부분의 스레드 할당은 Java EE 컨테이너에서 수행되므로 스레드 스택 추적을 이해하고 인식하고 스레드 스택 데이터에서 이를 식별할 수 있는 것이 중요합니다. 이를 통해 어떤 유형인지 빠르게 알 수 있습니다.
스레드 덤프 스택의 분석 관점에서 JVM이 발견한 스레드 풀 간의 차이점을 이해하고 요청 유형을 식별할 수 있습니다.
마지막 섹션에서는 HotSop VM용 JVM 스레드 스택이 무엇인지에 대한 개요와 앞으로 접하게 될 다양한 스레드에 대해 설명합니다. IBM VM 스레드 스택 형식에 대한 자세한 내용은 섹션 4에서 제공됩니다.
근본 원인 분석 포럼에서 이 기사에 대한 스레드 스택 예제를 얻을 수 있습니다.
JVM 스레드 스택 - 정의
JVM 스레드 스택은 생성된 모든 Java 스레드의 전체 목록을 제공하는 특정 시간의 스냅샷입니다.
검색된 각 Java 스레드는 다음 정보를 제공합니다.
– 스레드 이름. 미들웨어 제조업체에서 스레드를 식별하는 데 자주 사용됩니다. 일반적으로 할당된 스레드 풀 이름과 상태(실행 중, 차단됨 등)도 전달합니다.
– 스레드 유형 및 우선순위(예: daemon prio=3 ** 미들웨어 프로그램은 일반적으로 백그라운드 데몬 형태로 스레드를 생성합니다. 즉, 이러한 스레드는 사용자에게 서비스를 제공합니다. 예: Java EE 애플리케이션 **
– Java 스레드 ID, 예: tid=0x000000011e52a800 ** java.lang.Thread.getId()를 통해 얻은 Java 스레드 ID로, 긴 자체 증가 Shaping 1..n으로 자주 사용됩니다.**
구현 – 네이티브 스레드 ID(예: nid=0x251c**), 네이티브 스레드 ID를 사용하면 운영 체제 관점에서와 같은 정보를 얻을 수 있기 때문에 키가 되는 이유 스레드가 JVM에서 대부분의 CPU 시간을 사용하고 있습니다. **
– Java 스레드 상태 및 세부 정보(예: 대기 중 모니터 항목 [0xfffffffea5afb000] java.lang.Thread .State: BLOCKED(객체 모니터에서) )
** 스레드 상태와 현재 차단의 가능한 이유를 빠르게 이해할 수 있습니다**
– Java 스레드 스택 추적은 지금까지 스레드 스택에서 수행할 수 있는 작업입니다. % 정보에서 찾은 데이터입니다.
– Java 힙 메모리 분해; HotSpot VM 버전 1.6부터 Java의 힙 메모리(YoungGen, OldGen) 및 PermGen 공간과 같은 스레드 스택 끝에서 HotSpot의 메모리 사용량을 볼 수 있습니다. 이 정보는 잦은 GC로 인해 발생하는 문제를 분석할 때 유용합니다. 알려진 스레드 데이터나 패턴을 사용하여 빠르게 현지화할 수 있습니다.
Heap PSYoungGen total 466944K, used 178734K [0xffffffff45c00000, 0xffffffff70800000, 0xffffffff70800000) eden space 233472K, 76% used [0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000) from space 233472K, 0% used [0xffffffff62400000,0xffffffff62400000,0xffffffff70800000) to space 233472K, 0% used [0xffffffff54000000,0xffffffff54000000,0xffffffff62400000) PSOldGen total 1400832K, used 1400831K [0xfffffffef0400000, 0xffffffff45c00000, 0xffffffff45c00000) object space 1400832K, 99% used [0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000) PSPermGen total 262144K, used 248475K [0xfffffffed0400000, 0xfffffffee0400000, 0xfffffffef0400000) object space 262144K, 94% used [0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee0400000)
스레드 스택 정보의 대규모 해체
더 나은 이해를 돕기 위해 다음 그림에서는 HotSpot VM의 스레드 스택 정보와 스레드를 제공합니다. Chi는 아래 그림과 같이 세부적으로 분해했습니다.
위 그림에서 볼 수 있듯이 스레드 스택은 여러 부분으로 구성됩니다. 이 정보는 모두 문제 분석에 중요하지만, 다양한 문제 패턴을 분석하기 위해 서로 다른 부분이 사용됩니다(문제 패턴은 이후 기사에서 시뮬레이션되고 시연됩니다.)
이제 이 분석을 통해 예를 들어 보겠습니다. HoteSpot에서 스레드 스택 정보의 다양한 구성 요소를 자세히 설명합니다.
# Full thread dump标示符
"전체 스레드 덤프"는 전역적으로 고유한 키워드이므로 미들웨어에서 사용할 수 있습니다. 출력에서 찾아보세요. 독립 실행형 Java 버전의 스레드 스택 정보 로그입니다(예: UNIX에서는 kill -3
전체 스레드 덤프 Java HotSpot(TM) 64비트 서버 VM(20.0-b11 혼합 모드):
# Java EE 미들웨어, 타사 및 사용자 정의 애플리케이션 소프트웨어의 스레드
이 부분은 전체 스레드 스택의 핵심 부분이자, 일반적으로 분석 시간이 가장 많이 걸리는 부분이기도 합니다. 스택의 스레드 수는 사용하는 미들웨어, 타사 라이브러리(독립 스레드가 있을 수 있음) 및 애플리케이션(사용자 정의 스레드를 생성하는 경우 일반적으로 좋은 방법이 아님)에 따라 다릅니다.
예제 스레드 스택에서 WebLogic은 우리가 사용하는 미들웨어입니다. Weblogic 9.2부터 "'weblogic.kernel.Default(self-tuning)"로 고유하게 식별되는 자체 관리 스레드 풀이 사용됩니다.
"[STANDBY] ExecuteThread: '414' for queue: 'weblogic.kernel.Default (self-tuning)'" daemon prio=3 tid=0x000000010916a800 nid=0x2613 in Object.wait() [0xfffffffe9edff000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xffffffff27d44de0> (a weblogic.work.ExecuteThread) at java.lang.Object.wait(Object.java:485) at weblogic.work.ExecuteThread.waitForRequest(ExecuteThread.java:160) - locked <0xffffffff27d44de0> (a weblogic.work.ExecuteThread) at weblogic.work.ExecuteThread.run(ExecuteThread.java:181)
# HotSpot VM Thread
Hotspot VM에서 관리하는 내부 스레드로 내부 네이티브 작업을 수행하는 데 사용됩니다. 일반적으로 (관련 스레드 스택 및 prstat 또는 기본 스레드 ID를 통해) 높은 CPU 사용량을 발견하지 않는 한 이에 대해 크게 걱정할 필요가 없습니다.
"VM Periodic Task Thread" prio=3 tid=0x0000000101238800 nid=0x19 waiting on condition
# HotSpot GC 스레드
병렬 GC를 위해 HotSpot을 사용하는 경우(현재 다중 물리적 코어를 사용하는 환경에서 일반적임) 기본적으로 생성된 HotSpot VM 또는 각 JVM은 특정 ID를 사용하여 GC 스레드를 관리합니다. 이러한 GC 스레드는 VM이 주기적 GC를 수행하도록 할 수 있습니다. 병렬 방식으로 정리하면 GC 시간이 전반적으로 단축되는 동시에 CPU 사용 시간이 늘어납니다.
"GC task thread#0 (ParallelGC)" prio=3 tid=0x0000000100120000 nid=0x3 runnable "GC task thread#1 (ParallelGC)" prio=3 tid=0x0000000100131000 nid=0x4 runnable ………………………………………………………………………………………………………………………………………………………………
这事非常关键的数据,因为当你遇到跟GC有关的问题,诸如过度GC、内存泄露等问题是,你将可以利用这些线程的原生Id值关联的操作系统或者Java线程,进而发现任何对CPI时间的高占用. 未来的文章你将会了解到如何识别并诊断这样的问题.
# JNI 全局引用计数
JNI (Java 本地接口)的全局引用就是从本地代码到由Java垃圾收集器管理的Java对象的基本的对象引用. 它的角色就是阻止对仍然在被本地代码使用,但是技术上已经不是Java代码中的“活动的”引用了的对象的垃圾收集.
同时为了侦测JNI相关的泄露而留意JNI引用也很重要. 如果你的程序直接使用了JNI,或者像监听器这样的第三方工具,就容易造成本地的内存泄露.
JNI global references: 1925
# Java 堆栈使用视图
这些数据被添加回了 JDK 1 .6 ,向你提供有关Hotspot堆栈的一个简短而快速的视图. 我发现它在当我处理带有过高CPU占用的GC相关的问题时非常有用,你可以在一个单独的快照中同时看到线程堆栈以及Java堆的信息,让你当时就可以在一个特定的Java堆内存空间中解析(或者排除)出任何的关键点. 你如在我们的示例线程堆栈中所见,Java 的堆 OldGen 超出了最大值!
Heap PSYoungGen total 466944K, used 178734K [0xffffffff45c00000, 0xffffffff70800000, 0xffffffff70800000) eden space 233472K, 76% used [0xffffffff45c00000,0xffffffff50ab7c50,0xffffffff54000000) from space 233472K, 0% used [0xffffffff62400000,0xffffffff62400000,0xffffffff70800000) to space 233472K, 0% used [0xffffffff54000000,0xffffffff54000000,0xffffffff62400000) PSOldGen total 1400832K, used 1400831K [0xfffffffef0400000, 0xffffffff45c00000, 0xffffffff45c00000) object space 1400832K, 99% used [0xfffffffef0400000,0xffffffff45bfffb8,0xffffffff45c00000) PSPermGen total 262144K, used 248475K [0xfffffffed0400000, 0xfffffffee0400000, 0xfffffffef0400000) object space 262144K, 94% used [0xfffffffed0400000,0xfffffffedf6a6f08,0xfffffffee040000
更多Java 스레드 스택에 대한 심층적인 JVM 분석相关文章请关注PHP中文网!