ทำไม JVM แคช JIT คอมไพล์โค้ดไม่ได้


107

การใช้งาน JVM ที่เป็นที่ยอมรับจาก Sun ใช้การเพิ่มประสิทธิภาพที่ค่อนข้างซับซ้อนบางอย่างกับ bytecode เพื่อให้ได้ความเร็วในการดำเนินการที่ใกล้เคียงกับเนทีฟหลังจากที่โค้ดถูกเรียกใช้ไปสองสามครั้ง

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

ตามที่กล่าวมาทุกครั้งที่เรียกใช้งานโปรแกรมคอมไพเลอร์ JIT จะเริ่มทำงานใหม่แทนที่จะใช้โค้ดเวอร์ชันที่คอมไพล์ไว้ล่วงหน้า การเพิ่มคุณสมบัตินี้จะไม่เพิ่มการเพิ่มที่สำคัญให้กับเวลารันเริ่มต้นของโปรแกรมเมื่อมีการตีความ bytecode เป็นหลักหรือไม่?


4
กระทู้ที่พูดถึงปัญหานี้: javalobby.org/forums/thread.jspa?threadID=15812
miku

2
แต่เป็นคำถามที่ไม่น่าจะดึงดูดคำตอบที่ชัดเจน
bmargulies

1
ฉันไม่แน่ใจเกี่ยวกับการเพิ่ม "สำคัญ" เพราะคุณจะต้องโหลดสิ่งที่ JITted จากดิสก์แทนการ JITing ลงในหน่วยความจำ มันสามารถเร่งความเร็วได้ แต่เป็นกรณี ๆ ไป
R. Martinho Fernandes

1
ขอบคุณสำหรับคำตอบที่ดีทุกคน! คำตอบทั้งหมดถูกต้องเท่ากันดังนั้นฉันจึงไปกับชุมชนในเรื่องนี้ ...
Chinmay Kanchi

นี่เป็นคำถามที่ดีถ้าคุณถามฉัน :)
Alfred

คำตอบ:


25

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

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


6
... หรือคุณก็สามารถมีความคงทนเป็นตัวเลือกเช่น Oracle ของ JVM ไม่ - Empower เขียนโปรแกรมขั้นสูงเพื่อเพิ่มประสิทธิภาพของแอพลิเคชันของพวกเขาเมื่อใดและที่พวกเขาเพียงแค่รู้ว่ารูปแบบจะไม่เปลี่ยนแปลงภายใต้ความรับผิดชอบของพวกเขา ทำไมจะไม่ล่ะ?!
Alex Martelli

2
เพราะมันคงไม่คุ้ม. หากทั้ง SUN, IBM และ BEA ไม่ได้พิจารณาว่ามันคุ้มค่าสำหรับ JVM ที่มีประสิทธิภาพก็จะมีเหตุผลที่ดี บางทีการเพิ่มประสิทธิภาพ RT ของพวกเขาอาจเร็วกว่าของ Oracle ซึ่งเป็นสาเหตุที่ Oracle แคชไว้
skaffman

9
ทำไมไม่ใช้การเพิ่มประสิทธิภาพที่จัดเก็บไว้เป็นจุดเริ่มต้นเพื่อใช้สิ่งที่ได้เรียนรู้ในการวิ่งครั้งก่อน จากนั้น JIT สามารถทำงานได้ตามปกติเพื่อเพิ่มประสิทธิภาพสิ่งต่างๆ เมื่อปิดเครื่องรหัสนั้นอาจคงอยู่อีกครั้งและใช้ในการรันครั้งถัดไปเป็นจุดเริ่มต้นใหม่
Puce

1
@Puce เหตุผลเดียวที่ฉันคิดได้คือ AFAIK คุณไม่มีสถิติการทำโปรไฟล์จากการเรียกใช้โค้ดที่ปรับให้เหมาะสม ดังนั้นคุณไม่มีทางที่จะปรับปรุง ...
maaartinus

1
โดยส่วนตัวแล้วฉันจะรู้สึกดีกับตัวเลือก "เพียงแค่ยืนยันข้อมูลการทำโปรไฟล์ JIT ระหว่างการรัน" พร้อมคำเตือนทั้งหมดที่ว่า "สิ่งนี้จะใช้ได้เฉพาะกับ JVM เดียวกันเท่านั้นข้อมูลเดียวกันและอื่น ๆ ที่ถูกละเว้น" เกี่ยวกับสาเหตุที่ไม่ได้นำไปใช้ฉันคาดหวังว่าความซับซ้อนที่เพิ่มขึ้นของการคงอยู่และการตรวจสอบความถูกต้องของข้อมูลเมล็ดพันธุ์ JIT นั้นมากเกินไปที่จะใช้ทรัพยากรจากโครงการอื่น ๆ ให้ทางเลือกระหว่างสิ่งนี้กับสตรีมแลมบ์ดา + Java 8 ฉันควรเลือกอย่างหลัง
Thorbjørn Ravn Andersen

25

JVM ของ Oracleมีเอกสารให้ทำเช่นนั้น - อ้างถึง Oracle,

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

ฉันไม่รู้ว่าทำไมการติดตั้ง VM ที่ซับซ้อนทั้งหมดจึงไม่มีตัวเลือกที่คล้ายกัน


8
เนื่องจาก JVM ที่มีความซับซ้อนอื่น ๆ ไม่มี RDBMS ระดับองค์กรที่ยอดเยี่ยมที่มีประโยชน์ในการจัดเก็บสิ่งต่างๆ :)
skaffman

ว้าว! นั่นหมายความว่าการรวบรวมจะถูกแคชไว้ตลอดเวลา นี่คือข่าวดี!
Sandeep Jindal

J9 ของไอบีเอ็มได้รับการบันทึกไว้เช่นกัน
user314104

9
โปรดทราบว่า Oracle JVM นี้เป็นหนึ่งใน Oracle Database ไม่ใช่ที่ Oracle ดาวน์โหลดมาเมื่อซื้อ Sun
Thorbjørn Ravn Andersen

14

อัปเดตเป็นคำตอบที่มีอยู่ - Java 8 มี JEP สำหรับแก้ปัญหานี้โดยเฉพาะ:

=> JEP 145: รหัสแคชรวบรวม ลิงค์ใหม่ .

เป้าหมายที่ระบุไว้ในระดับที่สูงมากคือ :

บันทึกและนำโค้ดเนทีฟที่คอมไพล์แล้วมาใช้ใหม่จากการรันก่อนหน้านี้เพื่อปรับปรุงเวลาเริ่มต้นของแอปพลิเคชัน Java ขนาดใหญ่

หวังว่านี่จะช่วยได้


3
คุณลักษณะนี้ยังไม่ได้ทำให้มันไปรุ่นสุดท้าย
assylias

5

Excelsior JETมีการแคชคอมไพเลอร์ JIT ตั้งแต่เวอร์ชัน 2.0 ซึ่งเปิดตัวในปี 2544 ยิ่งไปกว่านั้นคอมไพเลอร์ AOT อาจคอมไพล์แคชใหม่เป็น DLL / อ็อบเจ็กต์เดียวที่ใช้ร่วมกันโดยใช้การปรับให้เหมาะสมทั้งหมด


3
ใช่ แต่คำถามเกี่ยวกับ JVM ที่เป็นที่ยอมรับคือ JVM ของ Sun ฉันทราบดีว่ามีคอมไพเลอร์ AOT หลายตัวสำหรับ Java รวมถึง JVM การแคชอื่น ๆ
Chinmay Kanchi

0

ฉันไม่ทราบเหตุผลที่แท้จริงไม่มีส่วนเกี่ยวข้องใด ๆ ในการติดตั้ง JVM แต่ฉันสามารถนึกถึงเหตุผลที่น่าจะเป็นไปได้:

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

แต่ฉันเดาจริงๆและอย่างที่คุณเห็นฉันไม่คิดว่าเหตุผลของฉันคือตัวหยุดการแสดงที่แท้จริง ฉันคิดว่าซันไม่ถือว่าการสนับสนุนนี้เป็นสิ่งสำคัญและบางทีเหตุผลแรกของฉันก็ใกล้เคียงกับความจริงเนื่องจากการทำเช่นนี้เป็นนิสัยอาจทำให้ผู้คนคิดว่าไฟล์คลาส Java ต้องการเวอร์ชันแยกต่างหากสำหรับแต่ละ VM แทนที่จะเป็น ข้ามแพลตฟอร์ม

วิธีที่ฉันต้องการจริงๆคือการมีตัวแปล bytecode-to-native แยกต่างหากที่คุณสามารถใช้เพื่อทำสิ่งนี้ล่วงหน้าอย่างชัดเจนโดยสร้างไฟล์คลาสที่สร้างขึ้นอย่างชัดเจนสำหรับ VM เฉพาะโดยอาจมี bytecode ดั้งเดิมอยู่ในนั้นเพื่อให้คุณ สามารถทำงานกับ VM ที่แตกต่างกันได้เช่นกัน แต่นั่นอาจมาจากประสบการณ์ของฉัน: ฉันใช้ Java ME เป็นส่วนใหญ่ซึ่งมันเจ็บมากที่คอมไพเลอร์ Java ไม่ฉลาดกว่าในการคอมไพล์


1
มีจุดหนึ่งในไฟล์คลาสสำหรับสิ่งนั้น infact ที่เป็นเจตนาดั้งเดิม (เก็บรหัส JIT'ed เป็นแอตทริบิวต์ในไฟล์คลาส)
TofuBeer

@TofuBeer: ขอบคุณสำหรับคำยืนยัน ฉันสงสัยว่าอาจเป็นอย่างนั้น (นั่นคือสิ่งที่ฉันจะทำ) แต่ไม่แน่ใจ แก้ไขเพื่อลบสิ่งนั้นออกด้วยเหตุผลที่เป็นไปได้
JaakkoK

ฉันคิดว่าคุณโดนตะปูที่หัวด้วยสัญลักษณ์แสดงหัวข้อย่อยสุดท้าย ส่วนอื่น ๆ สามารถแก้ไขได้ แต่ส่วนสุดท้ายคือฉันคิดว่าเหตุผลหลักที่รหัส JITed ไม่คงอยู่
Sasha Chedygov

1
ย่อหน้าสุดท้ายเกี่ยวกับคอมไพเลอร์ bytecode-to-native ที่ชัดเจนคือสิ่งที่คุณมีอยู่ใน. NET ที่มี NGEN ( msdn.microsoft.com/en-us/library/6t9t5wcf(VS.71).aspx )
R Martinho Fernandes
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.