ในบทความนี้ฉันจะสอนวิธีวิเคราะห์สแต็กเธรดของ JVM และวิธีการค้นหาสาเหตุของปัญหาจากข้อมูลสแต็ก ในความคิดของฉันเทคโนโลยีการวิเคราะห์ด้ายสแต็คเป็นเทคโนโลยีที่วิศวกรสนับสนุนผลิตภัณฑ์ Java EE ต้องเชี่ยวชาญ ข้อมูลที่เก็บไว้ในสแต็กเธรดมักจะเกินจินตนาการของคุณ
เป้าหมายของฉันคือการแบ่งปันความรู้และประสบการณ์ที่สะสมในการวิเคราะห์ด้ายในช่วงสิบปีที่ผ่านมา ความรู้และประสบการณ์เหล่านี้ได้รับในการวิเคราะห์เชิงลึกของ JVM รุ่นต่าง ๆ และซัพพลายเออร์ JVM ของผู้ผลิตหลายราย
ดังนั้นคุณพร้อมแล้วตอนนี้บทความนี้จะถูกเพิ่มเข้าไปในบุ๊กมาร์ก คุณจะรออะไรโปรดรีบเร่งและแบ่งปันแผนการฝึกอบรมการวิเคราะห์หัวข้อนี้กับเพื่อนร่วมงานและเพื่อนของคุณ
มันฟังดูดี
ข้อเสนอแนะของฉันคือการติดตามฉันเพื่อทำแผนการฝึกอบรมการวิเคราะห์หัวข้อนี้ นี่คือเนื้อหาการฝึกอบรมที่เราจะครอบคลุม ในเวลาเดียวกันฉันจะแบ่งปันกรณีจริงกับคุณที่ฉันได้จัดการกับทุกคนเพื่อเรียนรู้และเข้าใจกับทุกคน
1) ภาพรวมของสแต็คเธรดและความรู้พื้นฐาน
2) หลักการและเครื่องมือที่เกี่ยวข้องของสแต็กเธรด
3) รูปแบบสแต็คของ JVM ที่แตกต่างกัน (Sun Hotspot, IBM JRE, Oracal JRockit)
4) บทนำและวิธีการวิเคราะห์
5) การวิเคราะห์สแต็คเธรดและเทคโนโลยีที่เกี่ยวข้อง
6) เทมเพลตปัญหาที่พบบ่อย (เธรดล็อคที่ตายแล้ว IO เรียกความตายการรีไซเคิลขยะ/ปัญหา outofmemoryError วัฏจักรตาย ฯลฯ )
7) ตัวอย่างเช่นการวิเคราะห์ปัญหาสแต็คเธรด
ฉันหวังว่าการฝึกอบรมชุดนี้จะนำความช่วยเหลือที่แท้จริงมาให้คุณดังนั้นโปรดให้ความสนใจกับการอัปเดตบทความรายสัปดาห์ต่อไป
แต่ฉันควรทำอย่างไรถ้าฉันมีคำถามใด ๆ ในกระบวนการศึกษาหรือไม่เข้าใจเนื้อหาในบทความ
ไม่ต้องกังวลเพียงแค่ปฏิบัติต่อฉันในฐานะที่ปรึกษาของคุณ คุณสามารถปรึกษาฉันด้วยคำถามใด ๆ เกี่ยวกับสแต็คเธรด (หากปัญหาไม่สามารถต่ำเกินไป) โปรดเลือกวิธีต่อไปนี้เพื่อติดต่อกับฉัน:
1) แสดงความคิดเห็นโดยตรงในบทความนี้ (หากคุณเสียใจคุณอาจไม่ระบุชื่อ)
2) ส่งข้อมูลสแต็คเธรดของคุณไปยังฟอรัมการวิเคราะห์สาเหตุ
3) ส่งอีเมลถึงฉันที่อยู่คือ@[email protected]
คุณช่วยฉันวิเคราะห์ปัญหาที่พบในผลิตภัณฑ์ของเราได้ไหม
แน่นอนถ้าคุณเต็มใจคุณสามารถส่งข้อมูลสแต็กสดของคุณผ่านฟอรัมการวิเคราะห์ทางไปรษณีย์หรือฟอรัมรูทเคป ปัญหาที่แท้จริงคือราชาแห่งการเรียนรู้เพื่อพัฒนาทักษะ
ฉันหวังว่าทุกคนจะชอบการฝึกอบรมนี้ ดังนั้นฉันจะพยายามอย่างเต็มที่เพื่อให้คุณมีวัสดุคุณภาพสูงและตอบคำถามต่าง ๆ ของคุณ
ก่อนที่จะแนะนำเทคโนโลยีการวิเคราะห์ด้ายสแต็กและรูปแบบปัญหาคุณต้องบอกเนื้อหาพื้นฐานก่อน ดังนั้นในโพสต์นี้ฉันจะครอบคลุมเนื้อหาพื้นฐานที่สุดเพื่อให้ทุกคนสามารถเข้าใจการมีปฏิสัมพันธ์ระหว่าง JVM, มิดเดิลแวร์และคอนเทนเนอร์ Java EE ได้ดีขึ้น
ภาพรวม Java VM
Java Virtual Machine เป็นพื้นฐานของแพลตฟอร์ม Jave EE เป็นสถานที่ที่มีการปรับใช้และใช้งานมิดเดิลแวร์และแอปพลิเคชัน
JVM ให้สิ่งต่อไปนี้กับซอฟต์แวร์มิดเดิลแวร์และโปรแกรม Java/Java EE ของคุณ:
(แบบฟอร์มไบนารี) โปรแกรม Java / Java EE การรันสภาพแวดล้อมบางอย่างของโปรแกรมลักษณะการทำงานและเครื่องมือ (โครงสร้างพื้นฐาน IO, โครงสร้างข้อมูล, การจัดการเธรด, ความปลอดภัย, การตรวจสอบ ฯลฯ )
การจัดสรรและการจัดการหน่วยความจำแบบไดนามิกด้วยความช่วยเหลือของการกู้คืนขยะ
JVM ของคุณสามารถอยู่ในระบบปฏิบัติการจำนวนมาก (Solaris, Aix, Windows, ฯลฯ ) และสามารถกำหนดค่าได้ตามเซิร์ฟเวอร์ทางกายภาพของคุณ
ปฏิสัมพันธ์ระหว่าง JVM และมิดเดิลแวร์
แผนภาพต่อไปนี้แสดงรูปแบบการโต้ตอบสูงระหว่าง JVM, มิดเดิลแวร์และแอปพลิเคชัน
การโต้ตอบที่เรียบง่ายและทั่วไปบางอย่างระหว่าง JVM มิดเดิลแวร์และแอพที่แสดงในรูป อย่างที่คุณเห็นการจัดสรรเธรดของแอปพลิเคชัน Java EE มาตรฐานเสร็จสมบูรณ์ระหว่างแกนกลางของส่วนกลางและ JVM (แน่นอนมีข้อยกเว้นแอปพลิเคชันสามารถเรียก API โดยตรงเพื่อสร้างเธรดวิธีนี้ไม่ธรรมดาและจำเป็นต้องระมัดระวังในระหว่างการใช้งาน)
ในเวลาเดียวกันโปรดทราบว่าบางเธรดได้รับการจัดการโดย JVM
เนื่องจากการกระจายเธรดส่วนใหญ่ทำโดยคอนเทนเนอร์ Java EE จึงเป็นสิ่งสำคัญที่จะเข้าใจและเข้าใจการติดตามสแต็กของเธรดและสามารถระบุได้จากข้อมูลสแต็กเธรดซึ่งเป็นสิ่งสำคัญสำหรับคุณ คำขอกำลังจะดำเนินการคอนเทนเนอร์ Java EE
จากมุมมองของการวิเคราะห์สแต็กที่เก็บเธรดคุณจะสามารถเข้าใจความแตกต่างระหว่างพูลเธรดที่ค้นพบจาก JVM และระบุประเภทของคำขอ
ส่วนสุดท้ายจะให้ภาพรวมของสแต็กเธรด JVM สำหรับ HOTSOP V ให้คุณ
โปรดทราบว่าคุณสามารถรับตัวอย่างเธรดสแต็กสำหรับบทความนี้จากเหตุผลพื้นฐาน
JVM เธรดสแต็ก -มันคืออะไร?
สแต็กเธรด JVM เป็นสแน็ปช็อตเวลาที่กำหนดซึ่งสามารถให้รายการที่สมบูรณ์ของเธรด Java ทั้งหมดที่สร้างขึ้น
กระทู้ Java ทุกตัวที่พบจะให้ข้อมูลต่อไปนี้:
ชื่อของเธรด;
ประเภทเธรดและลำดับความสำคัญ: Daemon Prio = 3 ** โปรแกรมมิดเดิลแวร์โดยทั่วไปจะสร้างเธรดของพวกเขาในรูปแบบของการปกครองพื้นหลังซึ่งหมายความว่าเธรดเหล่านี้กำลังทำงานอยู่ในพื้นหลัง ไปยังแอปพลิเคชัน Java EE ของคุณ **
Java Thread ID เช่น: TID = 0x000000011E52A800 ** นี่คือรหัสเธรด Java ที่ได้รับผ่าน java.lang.thread.getId ()
ID เธรดดั้งเดิมเช่น: NID = 0x251C ** คีย์เป็นเพราะ ID เธรดดั้งเดิมช่วยให้คุณได้รับข้อมูลจากระบบปฏิบัติการ
สถานะเธรด Java และข้อมูลโดยละเอียดเช่น: รอรายการจอภาพ [0xffffffea5afb000] java.lang.thread.state: บล็อก (บนวัตถุตรวจสอบวัตถุ)
** คุณสามารถเข้าใจเหตุผลที่เป็นไปได้อย่างรวดเร็วว่าทำไมสถานะเธรดจึงถูกบล็อกอย่างมากในปัจจุบัน **
การติดตามสแต็กของ Java; สาเหตุของปัญหาหลายประเภท 90%ของข้อมูลที่ต้องการ
การสลายตัวของหน่วยความจำ Java Stack; ข้อมูลนี้มีประโยชน์มากเมื่อวิเคราะห์ปัญหาที่เกิดจาก GCs บ่อยครั้ง คุณสามารถใช้ข้อมูลเธรดหรือโหมดที่รู้จักเพื่อสร้างตำแหน่งที่รวดเร็ว
HEAPPSYNGGEN รวม 466944K, ใช้ 178734K [0xFFFFFFFF45C00000, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF F45 ffffffffffff62400000, 0xFFFFFFFF62400000,0XFFFFFFFFF60800000) E 233472K, 0% USERD [0xFFFFFFFFF54000000, 0xFFFFFFFFF5400000000 , 0XFFFFFFFFF62400000) PSOLDGEN TOTAL 1400832K, USED 1400831K [0xffffffffef0400000, 0xffffff45c00000, 0xFFFFFFFFF45C00000) Object Space 1400832K, 99% Used [0xffffffFFFFFFFEF0400000, 0XFFFFFFFFF45BFFFFB8,0XFFFFFFFFFFF45C00000) PSPERMGEN TOTAL 262144K, USED 248475K , 0xffffffee0400000, 0xFFFFFFFFFF0400000) Object Space 262144K, 94 % used [0xffffffffed0400000 , 0xFFFFFFEDF6F08,0XFFFFFFFFFFFFEE0400000)
การถอดชิ้นส่วนข้อมูลสแต็กของเธรดขนาดใหญ่
เพื่อให้ทุกคนเข้าใจได้ดีขึ้นรูปภาพต่อไปนี้จะถูกจัดเตรียมไว้ให้ทุกคน
ในรูปด้านบนจะเห็นได้ว่าสแต็กเธรดประกอบด้วยหลายส่วนที่แตกต่างกัน ข้อมูลนี้มีความสำคัญสำหรับการวิเคราะห์ปัญหา แต่การวิเคราะห์โหมดปัญหาที่แตกต่างกันจะใช้ส่วนต่าง ๆ (โหมดปัญหาจะจำลองและแสดงในบทความในภายหลัง)
ตอนนี้ผ่านตัวอย่างการวิเคราะห์นี้ฉันจะอธิบายรายละเอียดส่วนประกอบของฮอทสปอตบนข้อมูลสแต็ก -เธรด:
# เต็มเธรดการถ่ายโอนข้อมูล
"Full Thread Dump" เป็นคำหลักเพียงอย่างเดียว นี่คือจุดเริ่มต้นของสแน็ปช็อตสแต็กเธรด
Full Thread Dump Java Hotspot (TM) เซิร์ฟเวอร์ 64 บิต VM (โหมดผสม 20.0-B11):
# มิดเดิลแวร์ Java EE, บุคคลที่สามและเธรดในซอฟต์แวร์แอปพลิเคชันที่กำหนดเอง
ส่วนนี้เป็นส่วนหลักของสแต็กเธรดทั้งหมดและเป็นส่วนที่มักจะต้องวิเคราะห์เวลา จำนวนของสแต็คกึ่งกลางขึ้นอยู่กับมิดเดิลแวร์ที่คุณใช้ห้องสมุดที่สาม (อาจมีเธรดอิสระ) และแอปพลิเคชันของคุณ (ถ้าคุณสร้างเธรดที่กำหนดเองนี่ไม่ใช่วิธีปฏิบัติที่ดี)
ในตัวอย่างเธรดสแต็ก WebLogic เป็นมิดเดิลแวร์ที่เราใช้ เริ่มต้นจาก WebLogic 9.2 คุณจะใช้พูลเธรดที่ไม่ซ้ำกันซึ่งสามารถจัดการได้โดย "
"[สแตนด์บาย] ExecutetHread: '414' สำหรับคิว: 'WebLogic.kernel.default (การปรับตัวเอง)' 'daemon prio = 3 tid = 0x000000010916a800 nid = 0x2613 ในวัตถุ. wait () รัฐ: การรอ (บนจอภาพวัตถุ) ที่ java.lang.object.wait (วิธีการดั้งเดิม) -รออยู่บน <0xffffff27d44de0> (weblogic.work.executetethread) work.work.cutethread.waitforrequest (executethread.java:160) -ล็อค <0xffffffffff27d44de0> (weblogic.work.executetethread) c.work.executethread.run (executethread.java:181)
# เธรดฮอตสปอต VM
นี่คือเธรดภายในที่จัดการโดย Hotspot VM สำหรับการดำเนินงานดั้งเดิมของการดำเนินงานภายใน โดยทั่วไปคุณไม่ต้องทำอะไรมากเกินไปเกี่ยวกับเรื่องนี้เว้นแต่คุณจะพบอัตราการประกอบอาชีพ CPU ที่สูงเว้นแต่คุณจะ (ผ่านสแต็คเธรดที่เกี่ยวข้องและ PRSTAT หรือ ID เธรดดั้งเดิม)
"VM task task task task task" VM "prio = 3 tid = 0x0000000101238800 nid = 0x19 รอเงื่อนไข
# เธรด Hotspot GC
เมื่อใช้ฮอตสปอตสำหรับ GC แบบขนาน (ตอนนี้เป็นเรื่องปกติในสภาพแวดล้อมของแกนกายภาพหลายแกน) เมื่อฮอตสปอต VM สร้างขึ้นโดยค่าเริ่มต้นหรือแต่ละ JVM จัดการเธรด GC ที่มีโลโก้เฉพาะ การล้างข้อมูล GC เป็นระยะจะทำให้เวลาลดลงโดยรวมของ GC;
"เธรดงาน GC#0 (parallelgc)" prio = 3 tid = 0x0000000100120000 nid = 0x3 runnable "กระทู้งาน GC#1 (ขนาน)" prio = 3 tid = 0x0000131000 nid = 0x444 …………………………………………………………………………………………………………………………………………………………………………………………………………………………………… ………………………………………………………………
นี่เป็นข้อมูลที่สำคัญเนื่องจากเมื่อคุณพบปัญหาที่เกี่ยวข้องกับ GC เช่น GC มากเกินไปและการรั่วไหลของหน่วยความจำคุณจะสามารถใช้ระบบปฏิบัติการหรือเธรด Java ที่เกี่ยวข้องกับค่า ID ดั้งเดิมของเธรดเหล่านี้แล้วค้นหาสิทธิ์ใด ๆ ถูกต้อง
# JNI จำนวนการอ้างอิงทั่วโลก
การอ้างอิงทั่วโลกของ JNI (อินเทอร์เฟซ Local Java) มาจากรหัสท้องถิ่นไปยังวัตถุพื้นฐานของวัตถุ Java ที่จัดการโดย Java Garbage Collector คอลเลกชันขยะ
ในขณะเดียวกันก็เป็นสิ่งสำคัญที่จะต้องให้ความสนใจกับการอ้างอิง JNI เพื่อตรวจจับการรั่วไหลของ JNI ที่เกี่ยวข้องกับ JNI
JNI Global Reference: 1925
# java stack ใช้มุมมอง
ข้อมูลเหล่านี้ได้รับการเพิ่มกลับไปที่ JDK 1.6 ให้มุมมองสั้น ๆ และรวดเร็วของสแต็คฮอตสปอต และกอง Java ในสแนปชอตแยกต่างหากเพื่อให้คุณสามารถวิเคราะห์ (หรือแยกออก) ในพื้นที่หน่วยความจำกอง Java ที่เฉพาะเจาะจงในเวลานั้น
HEAP PSYOUNGGEN รวม 466944K, ใช้ 178734K [0xFFFFFF45C00000, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ffffffff62400000, 0xFFFFFFFF62400000,0XFFFFFFFFFF60800000) E 233472K, 0% ใช้ [0xFFFFFFFFF54000000, 0xffffffff540000, 0xFFFFFFFFF62400000) PSOLDGEN TOTAL 1400832k, Used 1400831K [0xffffffef0400000, 0xffffffffffffffffff, 0XFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFI FF45C00000) Object space 1400832k, 99% USED [0xffffffFFFFEF0400000,0XFFFFFFFFFF45BFFFFB8,0XFFFFFFFFF45C00000) PSPERMGEN TOTAL 262144K, USED 248475K [0 XFFFFFFFFFED0400000, 0xFFFFFFFFFEE0400000, 0xFFFFFFFFFEF0400000) Object Space 262144K, ใช้ 94% [0xffffffffffed0400000,0xffffffffffff6a6f08,0xffffffffffffe040000