เหตุใดจึงใช้ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุใดจึงใช้ JMH
- การเขียนการวัดประสิทธิภาพ
- การอุ่นเครื่องและรอบการทำงาน
- การหลีกเลี่ยงการลบโค้ดที่ไม่ก่อผล