ฉันกำลังคิดที่จะสร้างเครื่องมือดีบั๊กสำหรับแอปพลิเคชัน Java ของฉัน
ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะได้รับการติดตามแบบสแต็กเหมือนException.printStackTrace()
แต่ไม่มีข้อผิดพลาดเกิดขึ้นจริงหรือไม่
เป้าหมายของฉันคือการทิ้งสแต็กเพื่อดูว่าใครเป็นผู้โทร
ฉันกำลังคิดที่จะสร้างเครื่องมือดีบั๊กสำหรับแอปพลิเคชัน Java ของฉัน
ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะได้รับการติดตามแบบสแต็กเหมือนException.printStackTrace()
แต่ไม่มีข้อผิดพลาดเกิดขึ้นจริงหรือไม่
เป้าหมายของฉันคือการทิ้งสแต็กเพื่อดูว่าใครเป็นผู้โทร
คำตอบ:
คุณยังสามารถลองThread.getAllStackTraces()
รับแผนที่การติดตามสแต็กสำหรับเธรดทั้งหมดที่ยังมีชีวิตอยู่
ใช่เพียงแค่ใช้
Thread.dumpStack()
public static void dumpStack() { new Exception("Stack trace").printStackTrace(); }
stderr
ซึ่งน่าจะเป็นความหมายของคำถาม
หากคุณต้องการการติดตามสำหรับเธรดปัจจุบันเท่านั้น (แทนที่จะเป็นเธรดทั้งหมดในระบบตามที่คำแนะนำของ Ram ทำ) ให้ทำดังนี้:
Thread.currentThread () getStackTrace ()
ในการค้นหาผู้โทรให้ทำ:
private String getCallingMethodName() {
StackTraceElement callingFrame = Thread.currentThread().getStackTrace()[4];
return callingFrame.getMethodName();
}
และเรียกวิธีการนั้นจากภายในวิธีที่ต้องรู้ว่าใครเป็นผู้โทร อย่างไรก็ตามคำเตือน: ดัชนีของกรอบการโทรภายในรายการอาจแตกต่างกันไปตาม JVM! ทุกอย่างขึ้นอยู่กับจำนวนการโทรที่มีอยู่ใน getStackTrace ก่อนที่คุณจะไปถึงจุดที่สร้างการติดตาม โซลูชันที่มีประสิทธิภาพมากขึ้นจะได้รับการติดตามและวนซ้ำมันมองหาเฟรมสำหรับ getCallingMethodName จากนั้นทำสองขั้นตอนต่อไปเพื่อค้นหาผู้โทรที่แท้จริง
คุณสามารถรับการติดตามสแต็กดังนี้:
Throwable t = new Throwable();
t.printStackTrace();
หากคุณต้องการเข้าถึงเฟรมคุณสามารถใช้ t.getStackTrace () เพื่อรับอาร์เรย์ของเฟรมสแต็ก
ระวังว่า stacktrace นี้ (เหมือนกัน) อาจหายไปบางเฟรมหากคอมไพเลอร์ฮอตสปอตกำลังยุ่งอยู่กับการปรับสิ่งต่างๆให้เหมาะสม
t.printStackTrace
t.printStackTrace(System.out)
log.log(Level.SEVERE, "Failed to do something", new Throwable());
ขอให้สังเกตว่า Thread.dumpStack () ส่งข้อยกเว้นจริง:
new Exception("Stack trace").printStackTrace();
คุณยังสามารถส่งสัญญาณไปยัง JVM เพื่อดำเนินการ Thread.getAllStackTraces () บนกระบวนการ Java ที่กำลังรันอยู่โดยส่งสัญญาณ QUIT ไปยังกระบวนการ
บน Unix / Linux ใช้:
kill -QUIT process_id
โดยที่ process_id คือหมายเลขกระบวนการของโปรแกรม Java ของคุณ
บน Windows คุณสามารถกด Ctrl-Break ในแอปพลิเคชันได้แม้ว่าโดยปกติคุณจะไม่เห็นสิ่งนี้เว้นแต่ว่าคุณกำลังใช้กระบวนการคอนโซล
JDK6 แนะนำตัวเลือกอื่นนั่นคือคำสั่ง jstack ซึ่งจะแสดงสแต็กจากกระบวนการ JDK6 ที่ทำงานอยู่บนคอมพิวเตอร์ของคุณ:
jstack [-l] <pid>
ตัวเลือกเหล่านี้มีประโยชน์มากสำหรับแอปพลิเคชันที่ทำงานในสภาพแวดล้อมการผลิตและไม่สามารถแก้ไขได้อย่างง่ายดาย มีประโยชน์อย่างยิ่งสำหรับการวินิจฉัยการหยุดชะงักของรันไทม์หรือปัญหาด้านประสิทธิภาพ
http://java.sun.com/developer/technicalArticles/Programming/Stacktrace/ http://java.sun.com/javase/6/docs/technotes/tools/share/jstack.html
หากคุณต้องการจับเอาท์พุท
StringWriter sw = new StringWriter();
new Throwable("").printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
Java 9 เปิดตัว StackWalker
คลาสและการสนับสนุนสำหรับการเดินสแต็ก
นี่เป็นตัวอย่างเล็ก ๆ น้อย ๆ จาก Javadoc:
walk
วิธีการเปิดกระแสต่อเนื่องStackFrames
สำหรับเธรดปัจจุบันและจากนั้นใช้ฟังก์ชั่นได้รับที่จะเดินStackFrame
กระแส สตรีมรายงานองค์ประกอบเฟรมสแต็กตามลำดับจากเฟรมด้านบนส่วนใหญ่ที่แสดงถึงจุดดำเนินการที่สแต็กถูกสร้างไปที่เฟรมส่วนใหญ่ด้านล่างStackFrame
กระแสถูกปิดเมื่อคืนวิธีการเดินเท้า หากมีความพยายามที่จะนำสตรีมที่ปิดกลับมาใช้ใหม่IllegalStateException
จะถูกโยนทิ้ง...
ในการถ่ายภาพสแต็กเฟรม 10 อันดับแรกของเธรดปัจจุบัน
List<StackFrame> stack = StackWalker.getInstance().walk(s -> s.limit(10).collect(Collectors.toList()));
คุณไม่จำเป็นต้องทำสิ่งนี้ในรหัส คุณสามารถแนบ Java HPROF เข้ากับกระบวนการของคุณและเมื่อใดก็ตามที่กด Control- \ เพื่อส่งออก heap dump, เธรดที่กำลังรัน ฯลฯ . . โดยไม่ทำให้รหัสแอปพลิเคชันของคุณยุ่ง นี่ค่อนข้างล้าสมัยไปแล้ว Java 6 มาพร้อมกับ GUI jconsole แต่ฉันก็ยังพบว่า HPROF มีประโยชน์มาก
คำตอบโดย Rob Di Marcostderr
อยู่ไกลโดยที่ดีที่สุดถ้าคุณมีความสุขที่จะส่งออกไปยัง
หากคุณต้องการจับภาพ a String
โดยมีบรรทัดใหม่ตามการติดตามปกติคุณสามารถทำได้:
Arrays.toString(Thread.currentThread().getStackTrace()).replace( ',', '\n' );