0Pricing
Java Academy · บทเรียน

เหตุใดจึงใช้ JMH

หลีกเลี่ยงข้อผิดพลาดในการวัดประสิทธิภาพแบบง่ายเกินไป

เหตุใดจึงใช้ JMH เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

เหตุใดจึงใช้ JMH

เครื่องมือ Java สำหรับทดสอบประสิทธิภาพส่วนย่อย (JMH) เป็นเครื่องมือมาตรฐานสำหรับวัดประสิทธิภาพของโค้ด Java ขนาดเล็ก การเขียนลูปจับเวลาเองแทบจะให้ตัวเลขผิดเสมอ เพราะ JVM เป็นสภาพแวดล้อมขณะทำงานที่ปรับให้เหมาะสมอย่างซับซ้อน

JMH มีไว้เพื่อจัดการกับกับดักเหล่านี้

การ Benchmark แบบไร้เดียงสา

ความพยายามครั้งแรกที่พบได้ทั่วไปคือการครอบลูปด้วย System.nanoTime() วิธีนี้ดูสมเหตุสมผล แต่มีข้อบกพร่องร้ายแรงสำหรับการทดสอบประสิทธิภาพระดับย่อย

public class Main {
    static int compute(int n) { return n * n + 7; }
    public static void main(String[] args) {
        long start = System.nanoTime();
        int sink = 0;
        for (int i = 0; i < 1_000_000; i++) sink = compute(i);
        long elapsed = System.nanoTime() - start;
        System.out.println("ns: " + elapsed + " sink=" + sink);
    }
}

ปัญหาที่ 1: การอุ่นเครื่องของคอมไพเลอร์แบบทันเวลา

JVM เริ่มต้นในโหมดแปลคำสั่ง และจะคอมไพล์เมธอดที่ทำงานบ่อยเป็นโค้ดเนทีฟหลังจากมีการเรียกใช้นับพันครั้งเท่านั้น Benchmark แบบไร้เดียงสาวัดทั้งช่วงแปลคำสั่งที่ช้าและช่วงคอมไพล์ที่เร็วรวมกัน ทำให้ค่าเฉลี่ยไม่มีความหมาย

JMH แก้ปัญหานี้ด้วยช่วง การอุ่นเครื่อง โดยเฉพาะ ซึ่งจะไม่นำผลลัพธ์ไปใช้

ปัญหาที่ 2: การลบโค้ดที่ไม่มีการใช้งาน

หากไม่เคยใช้ผลลัพธ์ที่คำนวณได้ คอมไพเลอร์แบบทันเวลาอาจลบการคำนวณทั้งหมดออกไป จากนั้น Benchmark ของคุณก็จะวัดเพียงลูปว่าง

JMH มีทั้งการใช้ค่าที่ส่งคืนและ แบล็กโฮล เพื่อป้องกันปัญหานี้

ปัญหาที่ 3: การพับค่าคงที่

หากอินพุตเป็นค่าคงที่ที่ทราบตั้งแต่เวลาคอมไพล์ คอมไพเลอร์แบบทันเวลาจะคำนวณคำตอบเพียงครั้งเดียวแล้วนำกลับมาใช้ซ้ำ ด้านล่างนี้ คอมไพเลอร์อาจแทนที่ลูปทั้งหมดด้วยค่าคงที่เพียงค่าเดียว

JMH ใช้ออบเจ็กต์ @State เพื่อทำให้อินพุตไม่เปิดเผยรายละเอียดต่อตัวปรับให้เหมาะสม

public class Main {
    public static void main(String[] args) {
        // 2 * 21 is constant; the JIT folds it to 42
        int result = 2 * 21;
        System.out.println(result);
    }
}

ปัญหาที่ 4: การปรับลูปให้เหมาะสม

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

JMH แทนที่ลูปของคุณด้วยจำนวนรอบการทำงานที่ควบคุมอย่างรอบคอบและจัดการด้วยตัวเอง

ปัญหาที่ 5: การแทนที่บนสแต็ก

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

สิ่งที่ JMH มีให้

  • รอบการ อุ่นเครื่อง ที่แยกต่างหากและไม่นำผลลัพธ์ไปใช้
  • รอบการ วัดผล หลายรอบพร้อมสถิติ
  • การแยกการทำงานไปยัง JVM ใหม่ เพื่อหลีกเลี่ยงการปนเปื้อนของข้อมูลประวัติการปรับให้เหมาะสม
  • แบล็กโฮล และการใช้ผลลัพธ์เพื่อป้องกันการลบโค้ดที่ไม่มีการใช้งาน
  • ออบเจ็กต์ @State เพื่อป้องกันการพับค่าคงที่

วิธีเรียกใช้งาน

JMH เป็นสิ่งที่ต้องเพิ่มแยกต่างหาก (org.openjdk.jmh) และโดยปกติจะเรียกใช้ผ่านตัวประมวลผลคำอธิบายประกอบร่วมกับการ build ของเมเวน/Gradle ซึ่งสร้าง JAR ที่เรียกใช้งานได้ คุณไม่สามารถเรียกใช้ Benchmark จาก main ธรรมดาเหมือนโค้ดทั่วไปได้

สถิติมีความสำคัญ

JMH ไม่ได้รายงานเพียงค่าเฉลี่ย แต่ยังรายงานค่าความคลาดเคลื่อน / ช่วงความเชื่อมั่นตลอดรอบการทำงานและการแยกกระบวนการด้วย ผลลัพธ์ 42.0 +/- 1.3 ns/op บอกทั้งค่ากลางและระดับความแปรผัน ซึ่งจำเป็นต่อการเชื่อถือผลการวัด

เมื่อใดควรเลือกใช้ JMH

ใช้ JMH เมื่อเปรียบเทียบการทำงานสองแบบในส่วนที่ถูกเรียกใช้บ่อย ตรวจสอบการปรับให้เหมาะสม หรือวัดการดำเนินการระดับนาโนวินาทีถึงไมโครวินาที สำหรับงานหยาบที่ใช้เวลาระดับวินาที เช่น อินพุต/เอาต์พุตหรือเครือข่าย การจับเวลาแบบนาฬิกาจริงมักเพียงพอ

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณว่าเหตุใดจึงจำเป็นต้องใช้ JMH

สรุปทบทวน

คุณได้เรียนรู้เหตุผลที่การทดสอบประสิทธิภาพระดับย่อยต้องใช้เครื่องมือรองรับ:

  • JVM จะอุ่นเครื่อง: โค้ดที่แปลคำสั่งจะกลายเป็นโค้ดคอมไพล์หลังจากมีการเรียกใช้หลายครั้งเท่านั้น
  • การลบโค้ดที่ไม่มีการใช้งานและการพับค่าคงที่อาจลบงานของคุณหรือคำนวณไว้ล่วงหน้า
  • การปรับลูปให้เหมาะสมและการแทนที่บนสแต็กทำให้ลูปที่เขียนเองให้ผลคลาดเคลื่อน
  • JMH เพิ่มการอุ่นเครื่อง รอบการวัดผล การแยกกระบวนการ แบล็กโฮล และสถิติ
  • เลือกใช้ JMH เมื่อวัดส่วนการทำงานที่ถูกเรียกบ่อยในระดับนาโนวินาที

คำถามที่พบบ่อย

บทเรียน “เหตุใดจึงใช้ JMH” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “เหตุใดจึงใช้ JMH” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “เหตุใดจึงใช้ JMH”

หลีกเลี่ยงข้อผิดพลาดในการวัดประสิทธิภาพแบบง่ายเกินไป คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “เหตุใดจึงใช้ JMH” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุใดจึงใช้ JMH
  2. การเขียนการวัดประสิทธิภาพ
  3. การอุ่นเครื่องและรอบการทำงาน
  4. การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล
← กลับไปที่ Java Academy