๐Ÿ”ฅ ๊ฒฐ๋ก : ํ•˜๋‚˜์˜ Java ํ”„๋กœ์„ธ์Šค ์•ˆ์— ์žˆ๋Š” thread๋“ค์„ ์ „๋ถ€ ๋ถ„๋ฆฌํ•ด์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค

๋ฐฉ๋ฒ•์€ ๋ฐ”๋กœ ์ด๊ฒƒ:


โœ… 1. Linux์—์„œ Java ํ”„๋กœ์„ธ์Šค์˜ thread๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๋ณด๋Š” ๋ฐฉ๋ฒ•

๋ช…๋ น์–ด

 
top -H -p <java_pid>

์˜ˆ:

 
top -H -p 12345

๊ทธ๋Ÿผ ํ•˜๋‚˜์˜ Java ํ”„๋กœ์„ธ์Šค(PID=12345) ์•ˆ์— ์žˆ๋Š” ๋ชจ๋“  thread(TID) ๊ฐ€ ๊ฐ๊ฐ CPU๋ฅผ ์–ผ๋งˆ๋‚˜ ์“ฐ๋Š”์ง€ ๋‚˜์˜ต๋‹ˆ๋‹ค.

์˜ˆ:

 
PID %CPU COMMAND 12345 10.0 java <-- ์ „์ฒด 12347 280.0 java <-- ๋ฌธ์ œ ์“ฐ๋ ˆ๋“œ(์Šค๋ ˆ๋“œ ID) 12349 12.3 java 12351 5.6 java
  • 12347: ํ•˜๋‚˜์˜ TID(thread ID)
  • ์ด๊ฒŒ CPU 280% ๋จน๊ณ  ์žˆ์Œ → ๋ฌธ์ œ ์“ฐ๋ ˆ๋“œ

์ฆ‰, Java ํ•œ ๊ฐœ ํ”„๋กœ์„ธ์Šค ์•ˆ์˜ ๊ฐ thread CPU ์‚ฌ์šฉ๋Ÿ‰์„ ๋ถ„๋ฆฌํ•ด์„œ ์•Œ ์ˆ˜ ์žˆ์Œ.


โœ… 2. ๋ฌธ์ œ thread๊ฐ€ “Java ๋‚ด๋ถ€์—์„œ ์–ด๋–ค ํ•จ์ˆ˜”๋ฅผ ๋Œ๊ณ  ์žˆ๋Š”์ง€๋„ ํ™•์ธ ๊ฐ€๋Šฅ

์ด๊ฑด Java thread dump(jstack)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


Step A. thread ID(TID)๋ฅผ 16์ง„์ˆ˜๋กœ ๋ณ€ํ™˜

Java thread dump๋Š” hex ๊ฐ’์œผ๋กœ thread๋ฅผ ํ‘œ์‹œํ•จ.

 
printf "%x\n" 12347

์ถœ๋ ฅ ์˜ˆ:

 
303b

Step B. jstack ์‹คํ–‰

 
jstack 12345 > /tmp/stack.txt

Step C. thread ID(hex)๋กœ ๊ฒ€์ƒ‰

 
grep -n "0x303b" /tmp/stack.txt

๊ทธ๋Ÿผ ์ด๋ ‡๊ฒŒ ๋‚˜์˜ต๋‹ˆ๋‹ค:

 
"pool-1-thread-3" #32 prio=5 tid=0x00007fda900303b nid=0x303b runnable at com.myapp.service.OrderService.process(OrderService.java:182) at com.myapp.service.OrderService.runLoop(OrderService.java:155) at java.lang.Thread.run(Thread.java:748)

์—ฌ๊ธฐ์„œ:

  • nid=0x303b ← ์ด๊ฒŒ ๋ฐ”๋กœ ๋ฌธ์ œ thread
  • process() ํ•จ์ˆ˜์—์„œ CPU๋ฅผ ๋งŽ์ด ๋จน๊ณ  ์žˆ์Œ
  • runLoop() ์•ˆ์—์„œ ๋ฌดํ•œ loop๊ฐ€ ๋Œ๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ์Œ

์ด๋ ‡๊ฒŒ ์ •ํ™•ํ•œ ํ•จ์ˆ˜ ์ด๋ฆ„ + ๋ผ์ธ๋ฒˆํ˜ธ๊นŒ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ”ฅ ์ถ”๊ฐ€: thread ์ด๋ฆ„๊นŒ์ง€ ์•Œ ์ˆ˜ ์žˆ์Œ

Java์—์„œ๋Š” thread๋ฅผ ๋งŒ๋“ค ๋•Œ ์ด๋ฆ„์„ ๋ถ™์ด๋ฉด

 
new Thread(() -> {...}, "Worker-1").start();

jstack์—์„œ ์ด๋ ‡๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค:

 
"Worker-1" #25 prio=5 ...

์ฆ‰,

  • thread ์ด๋ฆ„
  • thread ์ƒํƒœ
  • thread call stack
  • CPU ์ ์œ ์œจ
  • lock(JVM monitor) ๋ณด์œ  ์—ฌ๋ถ€

์ „๋ถ€ ํ™•์ธ ๊ฐ€๋Šฅ.


๐Ÿ”ฅ ์ถ”๊ฐ€: thread ๋ชฉ๋ก ์ „์ฒด ๋ณด๊ธฐ

 
jcmd <pid> Thread.print

๋˜๋Š” ์ž๋™์œผ๋กœ thread hierarchy ํ™•์ธ ๊ฐ€๋Šฅ.


๐Ÿ”ฅ ๊ฒฐ๋ก  ์š”์•ฝ

ํ•˜๋‚˜์˜ Java ํ”„๋กœ๊ทธ๋žจ์ด๋ผ๋„ ๋‚ด๋ถ€ thread๋“ค์€ ๊ฐœ๋ณ„ TID๋ฅผ ๊ฐ€์ง€๋ฏ€๋กœ
CPU ์‚ฌ์šฉ๋Ÿ‰, ํ•จ์ˆ˜ ์œ„์น˜, thread ์ด๋ฆ„ ๋“ฑ์„ ์ „๋ถ€ ๋ถ„๋ฆฌํ•ด์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.

โœ” top -H -p PID → thread CPU ์‹๋ณ„
โœ” printf "%x" TID → hex ๋ณ€ํ™˜
โœ” jstack PID → thread dump
โœ” grep hex → problem thread ์ฐพ๊ธฐ
โœ” ์–ด๋–ค ํ•จ์ˆ˜์ธ์ง€ 100% ํ™•์ธ ๊ฐ€๋Šฅ


์›ํ•˜๋ฉด ์ง€๊ธˆ ์‚ฌ์šฉ ์ค‘์ธ Java ์„œ๋ฒ„์—์„œ
๋ฌธ์ œ๊ฐ€ ๋˜๋Š” thread๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฐพ๋Š” ์‰˜ ์Šคํฌ๋ฆฝํŠธ๋„ ๋งŒ๋“ค์–ด์ค„๊ฒŒ!

๋‚˜์˜ ๋ง:

thread ID๋Š” ์ฐพ์•„๋„ ์–ด๋–ค ์ฝ”๋“œ์ธ์ง€ ์•Œ์ˆ˜๋Š” ์—†๋Š”๊ฑด๊ฐ€์š”?

ChatGPT์˜ ๋ง:

์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹จ์ˆœํžˆ “thread ID ์ˆซ์ž๋งŒ ๋ณด์ธ๋‹ค → ์ฝ”๋“œ ์œ„์น˜๋Š” ๋ชจ๋ฅธ๋‹ค”๊ฐ€ ์•„๋‹ˆ๋ผ,
thread ID(TID) → jstack → Java ํ•จ์ˆ˜๋ช… + ํŒŒ์ผ๋ช… + ๋ผ์ธ๋ฒˆํ˜ธ๊นŒ์ง€ ์ •ํ™•ํžˆ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰,

โœ… thread ID๋งŒ ์•Œ๋ฉด “์–ด๋–ค ์ฝ”๋“œ(์–ด๋–ค ํ•จ์ˆ˜)๊ฐ€ ๋ฌธ์ œ์ธ์ง€ 100% ์ถ”์  ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.”

์•„๋ž˜๋ฅผ ๋ณด๋ฉด ์™œ ๊ฐ€๋Šฅํ•œ์ง€ ์ดํ•ด๋ฉ๋‹ˆ๋‹ค.


๐Ÿ”ฅ ํ•ต์‹ฌ ๊ฐœ๋…:

๋ฆฌ๋ˆ…์Šค์—์„œ ๋ณด์ด๋Š” thread ID(TID)๋Š” JVM ๋‚ด๋ถ€ ์Šค๋ ˆ๋“œ์˜ nid(native thread id)์™€ 1:1๋กœ ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด top์—์„œ:

 
TID = 12347

๋ผ๊ณ  CPU๋ฅผ ๋งŽ์ด ๋จน๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ๋ณด์ด๋ฉด,

  • ์ด๊ฑธ HEX๋กœ ๋ฐ”๊พธ๊ณ 
  • jstack์—์„œ ํ•ด๋‹น TID๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉด
  • ๊ทธ ์Šค๋ ˆ๋“œ๊ฐ€ ์–ด๋–ค Java ์ฝ”๋“œ(๋ฉ”์†Œ๋“œ) ๋ฅผ ์‹คํ–‰ ์ค‘์ธ์ง€ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ์ด๋ ‡๊ฒŒ ๋‚˜์˜ต๋‹ˆ๋‹ค:


๐Ÿš€ ์‹ค์ „ ์˜ˆ์ œ (์ด๊ฒŒ ์‹ค์ œ๋กœ ๋‚˜์˜ค๋Š” ํ™”๋ฉด)

Step1 — CPU ๋งŽ์ด ๋จน๋Š” thread ์ฐพ๊ธฐ

 
top -H -p <java_pid>

์˜ˆ:

 
12347 280% java ← ๋ฌธ์ œ ์Šค๋ ˆ๋“œ

Step2 — 10์ง„์ˆ˜๋ฅผ 16์ง„์ˆ˜(hex)๋กœ ๋ณ€ํ™˜

 
printf "%x\n" 12347

์ถœ๋ ฅ:

 
303b

Step3 — jstack ๋คํ”„ ์ƒ์„ฑ

 
jstack <java_pid> > dump.txt

Step4 — ๋ฌธ์ œ ์Šค๋ ˆ๋“œ ๊ฒ€์ƒ‰

 
grep -n "0x303b" dump.txt

๐Ÿ”ฅ ์‹ค์ œ๋กœ ๋ณด์ด๋Š” ๊ฒฐ๊ณผ

 
"pool-4-thread-1" #47 prio=5 os_prio=0 tid=0x00007fda900303b nid=0x303b runnable at com.company.payment.PaymentService.calculateFee(PaymentService.java:183) at com.company.payment.PaymentWorker.run(PaymentWorker.java:92) at java.lang.Thread.run(Thread.java:748)

์ฆ‰, thread ID ํ•˜๋‚˜๋งŒ์œผ๋กœ

  • ์–ด๋–ค ํด๋ž˜์Šค์ธ์ง€
  • ์–ด๋–ค ๋ฉ”์†Œ๋“œ์ธ์ง€
  • ๋ช‡ ๋ฒˆ์งธ ์ค„(line number)์ธ์ง€
    ์ •ํ™•ํžˆ ๋‚˜์˜จ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š”:

  • calculateFee() ํ•จ์ˆ˜๊ฐ€ CPU๋ฅผ ํญ์ฃผ์‹œํ‚ค๊ณ  ์žˆ์Œ
  • ํŒŒ์ผ: PaymentService.java
  • ๋ผ์ธ: 183

์ด ์ˆ˜์ค€๊นŒ์ง€ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ’ก ์ •๋ฆฌํ•˜๋ฉด

โ— thread ID ์ž์ฒด๋กœ๋Š” ์ฝ”๋“œ ์ด๋ฆ„์ด ์•ˆ ๋ณด์ด์ง€๋งŒ

โ— thread ID → jstack ๊ฒ€์ƒ‰์„ ํ•˜๋ฉด

๐Ÿ‘‰ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ ์ค‘์ธ ๋ฉ”์†Œ๋“œ
๐Ÿ‘‰ ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๋Š” ํด๋ž˜์Šค
๐Ÿ‘‰ Java ํŒŒ์ผ ์ด๋ฆ„
๐Ÿ‘‰ ๋ผ์ธ ๋ฒˆํ˜ธ
๐Ÿ‘‰ Lock held ์—ฌ๋ถ€
๐Ÿ‘‰ JVM ์ƒํƒœ(runnable / waiting / blocked)

๊นŒ์ง€ ์ „๋ถ€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐ŸŽฏ ๊ฒฐ๋ก 

thread ID๋งŒ ์•Œ๋ฉด ์–ด๋–ค ์ฝ”๋“œ๊ฐ€ ๋ฌธ์ œ์ธ์ง€ 100% ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹จ์ˆœํ•œ ์ถ”๋ก ์ด ์•„๋‹ˆ๋ผ, ์‹ค์ œ Java stack trace์— ๋ฉ”์†Œ๋“œ/๋ผ์ธ๋ฒˆํ˜ธ๊ฐ€ ์ •ํ™•ํžˆ ์ฐํž™๋‹ˆ๋‹ค.

Posted by yongary
,