โปรดจำไว้ว่าสิ่งต่อไปนี้เป็นการเปรียบเทียบความแตกต่างระหว่างการรวบรวมดั้งเดิมและ JIT เท่านั้นและไม่ครอบคลุมถึงเฉพาะของภาษาหรือกรอบงานใด ๆ อาจมีเหตุผลที่ถูกต้องในการเลือกแพลตฟอร์มใด ๆ นอกเหนือจากนี้
เมื่อเราอ้างว่าเนทีฟโค้ดนั้นเร็วกว่าเรากำลังพูดถึงกรณีการใช้งานทั่วไปของโค้ดที่คอมไพล์เมื่อเทียบกับโค้ดที่คอมไพล์แล้วของ JIT ซึ่งการใช้งานทั่วไปของแอปพลิเคชันที่รวบรวม JIT นั้นจะต้องดำเนินการโดยผู้ใช้ รอคอมไพเลอร์ก่อน) ในกรณีนี้ฉันไม่คิดว่าใคร ๆ ก็สามารถเรียกร้องด้วยหน้าตาตรงที่ JIT ที่คอมไพล์แล้วสามารถจับคู่หรือเอาชนะรหัสเนทีฟได้
สมมติว่าเรามีโปรแกรมที่เขียนในภาษา X และเราสามารถคอมไพล์มันด้วยคอมไพเลอร์เนทีฟและอีกครั้งด้วยคอมไพเลอร์ JIT แต่ละขั้นตอนการทำงานมีขั้นตอนเดียวกันที่เกี่ยวข้องซึ่งสามารถกำหนดเป็น (รหัส -> การเป็นตัวแทนระดับกลาง -> รหัสเครื่อง -> การดำเนินการ) ความแตกต่างที่สำคัญระหว่างสองคือผู้ใช้จะเห็นสเตจใด ด้วยการคอมไพล์เนทีฟโปรแกรมเมอร์จะเห็นทั้งหมดยกเว้นขั้นตอนการดำเนินการ แต่ด้วยโซลูชัน JIT ผู้ใช้จะเห็นการคอมไพล์ไปยังรหัสเครื่องนอกเหนือจากการประมวลผลแล้ว
การอ้างสิทธิ์ว่าA เร็วกว่า Bหมายถึงเวลาที่โปรแกรมใช้ในการทำงานตามที่ผู้ใช้เห็น หากเราสมมติว่าโค้ดทั้งสองชิ้นทำงานเหมือนกันในขั้นตอนการดำเนินการเราต้องสมมติว่ากระบวนการทำงานของ JIT ช้าลงสำหรับผู้ใช้เนื่องจากเขาต้องดูเวลา T ของการรวบรวมไปยังรหัสเครื่องโดยที่ T> 0 ดังนั้น เพื่อความเป็นไปได้ของกระบวนการทำงานของ JIT ที่จะดำเนินการเช่นเดียวกับขั้นตอนการทำงานดั้งเดิมสำหรับผู้ใช้เราจะต้องลดเวลาการเรียกใช้โค้ดเช่น Execution + Compilation ไปยังรหัสเครื่องต่ำกว่าขั้นตอนการเรียกใช้งานเท่านั้น ของกระบวนการทำงานดั้งเดิม ซึ่งหมายความว่าเราต้องปรับรหัสให้เหมาะสมในการคอมไพล์ JIT มากกว่าการคอมไพล์เนทีฟ
อย่างไรก็ตามการทำเช่นนี้ค่อนข้างเป็นไปไม่ได้เนื่องจากการดำเนินการปรับให้เหมาะสมที่จำเป็นเพื่อเพิ่มความเร็วในการดำเนินการเราต้องใช้เวลามากขึ้นในขั้นตอนการคอมไพล์จนถึงรหัสเครื่องดังนั้นทุกครั้งที่เราบันทึกเนื่องจากรหัสที่ได้รับการปรับปรุง เราเพิ่มลงในการรวบรวม กล่าวอีกนัยหนึ่ง "ความช้า" ของโซลูชันตาม JIT ไม่ใช่เพียงเพราะเวลาเพิ่มสำหรับการคอมไพล์ JIT แต่โค้ดที่สร้างโดยการคอมไพล์นั้นทำงานช้ากว่าโซลูชันเนทีฟ
ฉันจะใช้ตัวอย่าง: การจัดสรรการลงทะเบียน เนื่องจากการเข้าถึงหน่วยความจำช้ากว่าการเข้าถึงการลงทะเบียนหลายพันเท่าเราจึงต้องการใช้การลงทะเบียนทุกที่ที่เป็นไปได้และมีการเข้าถึงหน่วยความจำน้อยที่สุดเท่าที่จะทำได้ แต่เรามีการลงทะเบียนจำนวน จำกัด และเราต้องรั่วไหลลงในหน่วยความจำ การลงทะเบียน หากเราใช้อัลกอริทึมการจัดสรรการลงทะเบียนซึ่งใช้เวลาในการคำนวณ 200ms และด้วยเหตุนี้เราจึงประหยัดเวลาในการประมวลผล 2 มิลลิวินาที - เราจะไม่ใช้เวลาที่ดีที่สุดสำหรับคอมไพเลอร์ JIT โซลูชันเช่นอัลกอริทึมของ Chaitin ซึ่งสามารถสร้างโค้ดที่ได้รับการปรับปรุงอย่างเหมาะสมนั้นไม่เหมาะสม
บทบาทของคอมไพเลอร์ JIT คือการสร้างสมดุลที่ดีที่สุดระหว่างเวลารวบรวมและคุณภาพของโค้ดที่ผลิตอย่างไรก็ตามด้วยอคติขนาดใหญ่ในเวลารวบรวมอย่างรวดเร็วเนื่องจากคุณไม่ต้องการให้ผู้ใช้รอ ประสิทธิภาพของโค้ดที่ถูกเรียกใช้จะช้ากว่าในกรณี JIT เนื่องจากคอมไพเลอร์เนทีฟไม่ได้ผูกมัด (มาก) ตามเวลาในการปรับโค้ดให้เหมาะสมดังนั้นมีอิสระที่จะใช้อัลกอริธึมที่ดีที่สุด ความเป็นไปได้ที่การคอมไพล์ + การดำเนินการโดยรวมสำหรับคอมไพเลอร์ JIT สามารถเอาชนะเวลาการดำเนินการสำหรับโค้ดที่คอมไพล์แล้วเท่านั้นคือ 0 อย่างมีประสิทธิภาพ
แต่ VMs ของเราไม่ได้ จำกัด อยู่เพียงแค่การรวบรวม JIT พวกเขาใช้เทคนิคการรวบรวมล่วงหน้าเวลาแคชการสลับร้อนและการปรับให้เหมาะสมที่สุด ดังนั้นขอแก้ไขการอ้างสิทธิ์ของเราว่าประสิทธิภาพเป็นสิ่งที่ผู้ใช้เห็นและ จำกัด เวลาในการดำเนินการโปรแกรม (สมมติว่าเราได้รวบรวม AOT) เราสามารถสร้างโค้ดการดำเนินการให้เทียบเท่ากับคอมไพเลอร์เนทีฟ (หรืออาจจะดีกว่า) การอ้างสิทธิ์ที่ยิ่งใหญ่สำหรับ VMs คือพวกเขาอาจจะสามารถสร้างรหัสคุณภาพที่ดีกว่าจากนั้นก็เป็นคอมไพเลอร์เนทีฟเพราะมันมีการเข้าถึงข้อมูลเพิ่มเติม - ซึ่งเป็นกระบวนการที่กำลังทำงานอยู่เช่นความถี่ในการใช้งานฟังก์ชันบางอย่าง จากนั้น VM สามารถใช้การปรับให้เหมาะสมแบบปรับตัวกับโค้ดที่สำคัญที่สุดผ่านการสลับร้อน
มีปัญหาเกี่ยวกับเรื่องนี้แม้ว่าจะถือว่าการปรับให้เหมาะสมที่แนะนำโดยโปรไฟล์และสิ่งนั้นเป็นสิ่งที่ไม่เหมือนใครสำหรับ VMs ซึ่งไม่เป็นความจริง เราสามารถนำไปใช้กับการคอมไพล์เนทีฟได้เช่นกัน - โดยการรวบรวมแอปพลิเคชันของเราด้วยการเปิดใช้งานการทำโปรไฟล์บันทึกข้อมูลแล้วคอมไพล์แอปพลิเคชันอีกครั้งด้วยโปรไฟล์นั้น อาจเป็นมูลค่าที่ชี้ให้เห็นว่าการแลกเปลี่ยนรหัสที่ร้อนแรงไม่ใช่สิ่งที่ผู้เรียบเรียง JIT เท่านั้นที่สามารถทำได้เราสามารถทำได้สำหรับรหัสเนทีฟแม้ว่าโซลูชั่นที่ใช้ JIT สำหรับการทำเช่นนี้จะมีให้ใช้ง่ายกว่าและง่ายกว่ามากสำหรับนักพัฒนา ดังนั้นคำถามใหญ่ก็คือ: VM สามารถให้ข้อมูลบางอย่างที่คอมไพล์เนทีฟไม่สามารถที่จะเพิ่มประสิทธิภาพของโค้ดของเราได้หรือไม่?
ฉันไม่เห็นตัวเอง เราสามารถใช้เทคนิคส่วนใหญ่ของ VM ทั่วไปกับโค้ดเนทีฟได้เช่นกัน - แม้ว่ากระบวนการจะเกี่ยวข้องมากกว่า ในทำนองเดียวกันเราสามารถใช้การปรับให้เหมาะสมของคอมไพเลอร์เนทีฟกลับไปยัง VM ซึ่งใช้การคอมไพล์ AOT หรือการปรับให้เหมาะสมที่สุด ความจริงก็คือความแตกต่างระหว่างการเรียกใช้โค้ดโดยกำเนิดและการรันใน VM นั้นไม่ใหญ่เท่าที่เราเชื่อ ในที่สุดพวกเขานำไปสู่ผลลัพธ์เดียวกัน แต่พวกเขาใช้วิธีที่แตกต่างเพื่อไปที่นั่น VM ใช้วิธีวนซ้ำในการสร้างโค้ดที่ปรับให้เหมาะสมซึ่งคอมไพเลอร์เนทีฟคาดหวังตั้งแต่เริ่มต้น (และสามารถปรับปรุงได้ด้วยวิธีวนซ้ำ)
โปรแกรมเมอร์ C ++ อาจยืนยันว่าเขาต้องการการปรับให้เหมาะสมจากการเริ่มต้นและไม่ควรรอให้ VM รู้วิธีการทำหากเป็นไปได้ นี่อาจเป็นจุดที่ถูกต้องกับเทคโนโลยีปัจจุบันของเราเนื่องจากระดับการเพิ่มประสิทธิภาพในปัจจุบันของ VMs ของเราด้อยกว่าสิ่งที่คอมไพเลอร์ดั้งเดิมสามารถเสนอได้ - แต่อาจไม่เป็นเช่นนั้นเสมอไปหากโซลูชัน AOT ใน VM ของเราปรับปรุงเป็นต้น