JVM จัดการข้อยกเว้นที่เกิดจากวิธีหลักอย่างไร


10

ฉันเข้าใจข้อยกเว้นขว้างพวกมันจัดการพวกมันและแพร่กระจายมันไปยังวิธีที่ต่ำกว่าใน call stack (เช่นthrows)

สิ่งที่ฉันไม่เข้าใจคือ:

public static void main(String[] args) throws Exception {
    ...
}

ตอนนี้ฉันคิดว่าในกรณีที่mainมีการโยนExceptionJVM จัดการ (ถูกต้อง?) หากเป็นเช่นนั้นคำถามของฉันคือ:

JVM จัดการข้อยกเว้นที่ส่งออกมาmainอย่างไร มันทำอะไร?

คำตอบ:


19

คุณอาจคิดว่าpublic static void mainวิธีการใน Java หรือmainฟังก์ชั่นใน C เป็นจุดเริ่มต้นที่แท้จริงของโปรแกรมของคุณ - แต่มันไม่ใช่ ภาษาระดับสูงทั้งหมด (รวมถึง C) มีรันไทม์ภาษาที่เริ่มต้นโปรแกรมแล้วโอนการควบคุมการไหลไปยังจุดเริ่มต้น ในกรณีของ Java การเริ่มต้นจะรวมถึง:

  • ตั้งค่า JVM
  • กำลังโหลดคลาสที่ต้องการ
  • การรันบล็อก initializer แบบสแตติก สิ่งนี้สามารถเรียกใช้งานโค้ดที่ผู้ใช้กำหนดก่อนmainถูกเรียกใช้ บล็อกเหล่านี้ไม่ควรโยนข้อยกเว้น

มีหลายวิธีที่จะใช้การจัดการข้อยกเว้น แต่สำหรับจุดประสงค์ของคำถามนี้พวกเขาทั้งหมดสามารถดูเป็นกล่องดำ อย่างไรก็ตามสิ่งสำคัญคือภาษารันไทม์จะต้องมีตัวจัดการข้อยกเว้นนอกสุดซึ่งจะตรวจจับข้อยกเว้นทั้งหมดที่ไม่ได้รับจากรหัสผู้ใช้ ตัวจัดการข้อยกเว้นนี้โดยปกติจะพิมพ์การติดตามสแต็กปิดโปรแกรมอย่างเป็นระเบียบและออกด้วยรหัสข้อผิดพลาด การปิดโปรแกรมอย่างถูกต้องรวมถึงการทำลายกราฟวัตถุการเรียกใช้ finalizers และการปลดปล่อยทรัพยากรเช่นหน่วยความจำการจัดการไฟล์หรือการเชื่อมต่อเครือข่าย

สำหรับวัตถุประสงค์ของการภาพประกอบคุณสามารถสร้างอิมเมจการห่อรันไทม์ของรหัสทั้งหมดในรูปลองขนาดยักษ์ที่ดูเหมือน

try {
    loadClasses();
    runInitializers();
    main(argv);
    System.exit(0);
} catch (Throwable e) {
    e.printStackTrace();
    System.exit(-1);
}

ยกเว้นว่ามันไม่จำเป็นสำหรับภาษาที่จะเรียกใช้งานโค้ดเช่นนี้ ความหมายเดียวกันสามารถนำไปใช้ในรหัสสำหรับthrow(หรือเทียบเท่า) ที่ค้นหาตัวจัดการข้อยกเว้นที่เกี่ยวข้องครั้งแรก


9

ทั้งหมดรหัส Java ทำงานในบริบทของการเป็นด้าย JavaDoc ที่เชื่อมโยงอธิบายถึงข้อผิดพลาดในการจัดการและเกณฑ์การออก แต่นี่คือส่วนสำคัญของมัน:

  • JVM หมุนตัวเองขึ้นและเตรียมสภาพแวดล้อมการดำเนินการ
  • JVM สร้างเธรดซึ่งจะรันmain()เมธอดโดยใช้พารามิเตอร์บรรทัดคำสั่งใด ๆ ที่เกี่ยวข้อง
  • JVM ตั้งค่าตัวจัดการข้อยกเว้นที่ไม่ได้ตรวจสอบค่าดีฟอลต์ซึ่งพิมพ์ข้อยกเว้นเป็นข้อผิดพลาดมาตรฐานและยกเลิก
  • JVM ดำเนินการเธรด

ในกรณีที่มีข้อยกเว้นที่ไม่ได้ตรวจสอบโปรแกรมจะตายอย่างมีประสิทธิภาพต่อรายการที่สามด้านบน พฤติกรรมนี้มีการระบุเพิ่มเติมในJava Language Specification, มาตรา 11.3


ข้อมูลเพิ่มเติม

คนอื่น ๆ ได้พูดถึงบล็อกแบบคงที่และวิธีการดำเนินการก่อนหน้าmain()นี้ อย่างไรก็ตามสิ่งนี้ต้องการคำอธิบายเพิ่มเติมเล็กน้อยเพื่อทำความเข้าใจอย่างถูกต้อง

เมื่อโหลดคลาสตัวโหลดคลาสต้องเริ่มต้นstatic finalสถานะทั้งหมดและรันstaticบล็อกทั้งหมดก่อนที่คลาสจะสามารถใช้เพื่อรวมอินสแตนซ์ของอินสแตนซ์ของคลาส (ด้านข้าง: สร้างคลาส Java ที่ค่าคงที่ของคลาสถูกเริ่มต้นในบล็อกแบบคงที่หลังจากสร้าง อินสแตนซ์ของคลาสและตัวสร้างอ้างอิงค่าคงที่ Boom!) อย่างไรก็ตามทั้งหมดนี้เกิดขึ้นในโลจิกคลาสโหลดเดอร์ก่อนที่โค้ดใด ๆ สามารถอ้างอิงคลาสได้ นอกจากนี้คลาสจะถูกโหลดในสิ่งที่เธรดอ้างถึงคลาส

สิ่งนี้หมายความว่าถ้าคลาสที่มีmain()การอ้างอิงคลาสอื่น (เช่นค่าคงที่คลาส) จากนั้นคลาสนั้นจะต้องโหลดก่อนที่จะmain()ดำเนินการเพื่อรวมบล็อกแบบคงที่ มิฉะนั้นบล็อกแบบคงที่จะดำเนินการดังกล่าวข้างต้น หากคลาสไม่สามารถโหลดได้คลาสจะมีอยู่main()จะไม่สามารถโหลดได้และโปรแกรมจะยุติการทำงาน

FYI อื่น: บล็อกคงสามารถโยน Errorsถูกโยนตามที่เป็นอยู่ Exceptionsเป็นสิ่งต้องห้าม (ข้อผิดพลาดในการรวบรวมเวลา) RuntimeExceptionsถูกห่อในExceptionInInitializerError เหล่านี้ได้รับการจัดการต่อจัดการข้อยกเว้น uncaught ซึ่งโดยทั่วไปจะฆ่าด้ายหรือโปรแกรมประยุกต์ (หัวข้อหลัก) จนกว่าคุณจะระมัดระวังห่ออ้างอิงชั้น (และโหลด) ใน-trycatch

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.