กลับไปหน้าบทความ

อ่าน 8 นาที

การรวบรวมแบบทันเวลาพอดี

การคอมไพล์แบบทันเวลาพอดี ( JIT ) (หรือการแปลแบบไดนามิกหรือการคอมไพล์ขณะรันไทม์ ) คือการคอมไพ ล์

การรวบรวมแบบทันเวลาพอดี

การคอมไพล์แบบทันเวลาพอดี ( JIT ) (หรือการแปลแบบไดนามิกหรือการคอมไพล์ขณะรันไทม์ ) [ 1 ]คือการคอมไพ ล์ โค้ดคอมพิวเตอร์ระหว่างการทำงานของโปรแกรมขณะรันไทม์แทนที่จะคอมไพล์ก่อนการทำงาน[ 2 ]ซึ่งอาจประกอบด้วยการแปลโค้ดต้นฉบับแต่โดยทั่วไปแล้วจะ เป็นการแปล ไบต์โค้ดเป็นโค้ดเครื่องซึ่งจะถูกดำเนินการโดยตรง ระบบที่ใช้คอมไพเลอร์ JIT มักจะวิเคราะห์โค้ดที่กำลังทำงานอยู่อย่างต่อเนื่อง และระบุส่วนของโค้ดที่ความเร็วที่เพิ่มขึ้นจากการคอมไพล์หรือการคอมไพล์ใหม่จะมากกว่าค่าใช้จ่ายในการคอมไพล์โค้ดนั้น

การคอมไพล์แบบ JIT เป็นการผสมผสานระหว่างสองแนวทางดั้งเดิมในการแปลงเป็นรหัสเครื่อง ได้แก่การคอมไพล์ล่วงหน้า (AOT) และการตีความซึ่งรวมข้อดีและข้อเสียของทั้งสองวิธีเข้าด้วยกัน[ 2 ]โดยคร่าวๆ การคอมไพล์แบบ JIT ผสมผสานความเร็วของโค้ดที่คอมไพล์แล้วเข้ากับความยืดหยุ่นของการตีความ พร้อมด้วยค่าใช้จ่ายของตัวตีความและค่าใช้จ่ายเพิ่มเติมของการคอมไพล์และการเชื่อมโยง (ไม่ใช่แค่การตีความ) การคอมไพล์แบบ JIT เป็นรูปแบบหนึ่งของการคอมไพล์แบบไดนามิกและอนุญาตให้มีการเพิ่มประสิทธิภาพแบบปรับตัวได้เช่นการคอมไพล์ใหม่แบบไดนามิกและการเพิ่มความเร็วเฉพาะสถาปัตยกรรมไมโคร[ nb 1 ] [ 3 ]การตีความและการคอมไพล์แบบ JIT เหมาะอย่างยิ่งสำหรับภาษาการเขียนโปรแกรมแบบไดนามิกเนื่องจากระบบรันไทม์สามารถจัดการกับ ประเภทข้อมูล ที่ผูกไว้ภายหลังและบังคับใช้การรับประกันความปลอดภัยได้

ประวัติศาสตร์

โดยทั่วไปแล้วคอมไพเลอร์ JIT ตัวแรกที่เผยแพร่ถือเป็นผลงานของJohn McCarthy ในภาษา LISPเมื่อปี พ.ศ. 2503 [ 4 ]ในบทความสำคัญของเขาเรื่อง"ฟังก์ชันแบบเรียกซ้ำของนิพจน์เชิงสัญลักษณ์และการคำนวณโดยเครื่องจักร ตอนที่ 1"เขาได้กล่าวถึงฟังก์ชันที่ถูกแปลระหว่างรันไทม์ ซึ่งช่วยลดความจำเป็นในการบันทึกเอาต์พุตของคอมไพเลอร์ลงในบัตรเจาะรู[ ​​5 ] (แม้ว่าสิ่งนี้จะเรียกได้แม่นยำกว่าว่า " ระบบคอมไพล์และทำงาน ") อีกตัวอย่างหนึ่งในยุคแรกคือผลงานของKen Thompsonซึ่งในปี พ.ศ. 2511 ได้นำเสนอหนึ่งในแอปพลิเคชันแรกๆ ของนิพจน์ปกติสำหรับการจับคู่รูปแบบในโปรแกรมแก้ไขข้อความQED [ 6 ]เพื่อความเร็วThompsonได้นำการจับคู่นิพจน์ปกติมาใช้โดย JIT กับโค้ดIBM 7094 บน ระบบ Compatible Time-Sharing System [ 4 ] เทคนิคที่มีอิทธิพลในการสร้างโค้ดที่คอมไพล์แล้วจากการตีความนั้นริเริ่มโดยJames G. Mitchell ในปี พ.ศ. 2513 ซึ่งเขาได้นำไป ใช้กับภาษาทดลองLC² [ 7 ] [ 8 ]

Smalltalk (ประมาณปี 1980) เป็นผู้บุกเบิกแง่มุมใหม่ของการคอมไพล์ JIT ตัวอย่างเช่น การแปลงเป็นรหัสเครื่องจะทำตามความต้องการ และผลลัพธ์จะถูกแคชไว้เพื่อใช้ในภายหลัง เมื่อหน่วยความจำเหลือน้อย ระบบจะลบโค้ดบางส่วนนี้และสร้างใหม่เมื่อจำเป็นอีกครั้ง[ 2 ] [ 9 ] ภาษา Selfของ Sun ได้ปรับปรุงเทคนิคเหล่านี้อย่างกว้างขวาง และครั้งหนึ่งเคยเป็นระบบ Smalltalk ที่เร็วที่สุดในโลก โดยทำความเร็วได้ถึงครึ่งหนึ่งของ Cที่ได้รับการปรับแต่ง[ 10 ]แต่เป็นภาษา การเขียนโปรแกรมเชิงวัตถุ อย่างสมบูรณ์

Self ถูก Sun ละทิ้งไป แต่การวิจัยยังคงดำเนินต่อไปในภาษา Java คำว่า "การคอมไพล์แบบทันเวลาพอดี" (Just-in-time compilation) ยืมมาจากคำศัพท์ทางการผลิตว่า " ทันเวลาพอดี" ( Just in time ) และได้รับความนิยมจาก Java โดย James Gosling ใช้คำนี้ตั้งแต่ปี 1993 [ 11 ]ปัจจุบัน JITing ถูกใช้โดยการใช้งานเครื่องเสมือน Java ส่วนใหญ่ เนื่องจากHotSpotสร้างขึ้นบนพื้นฐานการวิจัยนี้และใช้งานอย่างกว้างขวาง

โครงการ HP Dynamo เป็นคอมไพเลอร์ JIT แบบทดลองที่รูปแบบ "ไบต์โค้ด" และรูปแบบรหัสเครื่องเหมือนกัน ระบบนี้ปรับรหัสเครื่องPA-8000 ให้เหมาะสม [ 12 ]ที่น่าประหลาดใจคือ ผลลัพธ์ที่ได้คือความเร็วที่เพิ่มขึ้น ในบางกรณีถึง 30% เนื่องจากการทำเช่นนี้ทำให้สามารถปรับให้เหมาะสมในระดับรหัสเครื่องได้ เช่น การอินไลน์โค้ดเพื่อการใช้แคชที่ดีขึ้น และการปรับให้เหมาะสมของการเรียกใช้ไลบรารีแบบไดนามิก รวมถึงการปรับให้เหมาะสมในระหว่างการทำงานอื่นๆ อีกมากมาย ซึ่งคอมไพเลอร์ทั่วไปไม่สามารถทำได้[ 13 ] [ 14 ]

ในเดือนพฤศจิกายน 2020 PHP 8.0 ได้แนะนำคอมไพเลอร์ JIT [ 15 ]ในเดือนตุลาคม 2024 CPythonได้แนะนำคอมไพเลอร์ JIT แบบทดลอง[ 16 ]

ออกแบบ

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

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

โดยทั่วไปโค้ด JIT จะให้ประสิทธิภาพที่ดีกว่าตัวแปลภาษามาก นอกจากนี้ ในบางกรณีอาจให้ประสิทธิภาพที่ดีกว่าการคอมไพล์แบบคงที่ เนื่องจากการปรับแต่งหลายอย่างสามารถทำได้เฉพาะในขณะรันไทม์เท่านั้น: [ 17 ] [ 18 ]

  1. การคอมไพล์สามารถปรับให้เหมาะสมกับซีพียูเป้าหมายและรุ่นของระบบปฏิบัติการที่แอปพลิเคชันทำงานอยู่ได้ ตัวอย่างเช่น JIT สามารถเลือกใช้ คำสั่งเวกเตอร์ SSE2ของซีพียูได้เมื่อตรวจพบว่าซีพียูรองรับคำสั่งเหล่านั้น เพื่อให้ได้ระดับการปรับแต่งที่เฉพาะเจาะจงเช่นนี้ด้วยคอมไพเลอร์แบบสแตติก จำเป็นต้องคอมไพล์ไบนารีสำหรับแต่ละแพลตฟอร์ม/สถาปัตยกรรมที่ต้องการ หรือไม่ก็ต้องรวมโค้ดหลายเวอร์ชันไว้ในไบนารีเดียว
  2. ระบบสามารถรวบรวมสถิติเกี่ยวกับการทำงานของโปรแกรมในสภาพแวดล้อมนั้นๆ และสามารถจัดเรียงและคอมไพล์ใหม่เพื่อให้ได้ประสิทธิภาพสูงสุด อย่างไรก็ตาม คอมไพเลอร์แบบสแตติกบางตัวก็สามารถรับข้อมูลโปรไฟล์เป็นอินพุตได้เช่นกัน
  3. ระบบสามารถทำการปรับแต่งโค้ดโดยรวม (เช่นการแทรก ฟังก์ชัน จากไลบรารี ) โดยไม่สูญเสียข้อดีของการเชื่อมโยงแบบไดนามิก และไม่มีค่าใช้จ่ายเพิ่มเติมที่เกิดขึ้นจากคอมไพเลอร์และลิงเกอร์แบบสแตติก โดยเฉพาะอย่างยิ่ง เมื่อทำการแทนที่แบบแทรกโค้ดโดยรวม กระบวนการคอมไพล์แบบสแตติกอาจต้องมีการตรวจสอบขณะรันไทม์และตรวจสอบให้แน่ใจว่าการเรียกใช้เสมือนจะเกิดขึ้นหากคลาสจริงของวัตถุเขียนทับเมธอดที่แทรกโค้ดไว้ และอาจต้องประมวลผลการตรวจสอบเงื่อนไขขอบเขตในการเข้าถึงอาร์เรย์ภายในลูป ด้วยการคอมไพล์แบบทันเวลา ในหลายกรณี การประมวลผลนี้สามารถย้ายออกจากลูปได้ ซึ่งมักจะทำให้ความเร็วเพิ่มขึ้นอย่างมาก
  4. แม้ว่าจะเป็นไปได้ในภาษาโปรแกรมที่คอมไพล์แบบคงที่และมีการจัดการหน่วยความจำอัตโนมัติ แต่ระบบไบต์โค้ดสามารถจัดเรียงโค้ดที่ถูกประมวลผลใหม่ได้ง่ายกว่าเพื่อการใช้แคชที่ดีขึ้น

เนื่องจาก JIT ต้องเรนเดอร์และเรียกใช้ภาพไบนารีเนทีฟในระหว่างการทำงาน JIT ที่เป็นรหัสเครื่องจริงจึงจำเป็นต้องใช้แพลตฟอร์มที่อนุญาตให้เรียกใช้ข้อมูลในระหว่างการทำงาน ทำให้การใช้ JIT ดังกล่าวบน เครื่องที่ใช้ สถาปัตยกรรม Harvardเป็นไปไม่ได้ เช่นเดียวกับระบบปฏิบัติการและเครื่องเสมือนบางระบบ อย่างไรก็ตาม JIT ประเภทพิเศษอาจไม่ได้มุ่งเป้าไปที่สถาปัตยกรรม CPU ของเครื่องจริง แต่เป็นไบต์โค้ด VM ที่ได้รับการปรับให้เหมาะสม ซึ่งมีข้อจำกัดเกี่ยวกับรหัสเครื่องดิบ โดยเฉพาะอย่างยิ่งในกรณีที่ VM ของไบต์โค้ดนั้นใช้ JIT กับรหัสเนทีฟในที่สุด[ 19 ]

ผลงาน

JIT ทำให้เกิดความล่าช้าเล็กน้อยไปจนถึงสังเกตได้ชัดเจนในการเริ่มต้นการทำงานของแอปพลิเคชัน เนื่องจากเวลาที่ใช้ในการโหลดและคอมไพล์โค้ดอินพุต บางครั้งความล่าช้านี้เรียกว่า "ความล่าช้าของเวลาเริ่มต้น" หรือ "เวลาอุ่นเครื่อง" โดยทั่วไป ยิ่ง JIT ทำการเพิ่มประสิทธิภาพมากเท่าใด โค้ดที่สร้างขึ้นก็จะยิ่งดีขึ้นเท่านั้น แต่ความล่าช้าเริ่มต้นก็จะเพิ่มขึ้นด้วย ดังนั้นคอมไพเลอร์ JIT จึงต้องแลกเปลี่ยนระหว่างเวลาในการคอมไพล์และคุณภาพของโค้ดที่หวังจะสร้างขึ้น เวลาเริ่มต้นอาจรวมถึงการดำเนินการที่เกี่ยวข้องกับ IO ที่เพิ่มขึ้น นอกเหนือจากการคอมไพล์ JIT ตัวอย่างเช่น ไฟล์ข้อมูลคลาส rt.jarสำหรับเครื่องเสมือน Java (JVM) มีขนาด 40 MB และ JVM ต้องค้นหาข้อมูลจำนวนมากในไฟล์ขนาดใหญ่ตามบริบทนี้[ 20 ]

การเพิ่มประสิทธิภาพที่เป็นไปได้วิธีหนึ่ง ซึ่งใช้โดยเครื่องเสมือน Java HotSpotของ Sun คือการรวมการตีความและการคอมไพล์ JIT เข้าด้วยกัน โค้ดแอปพลิเคชันจะถูกตีความในขั้นต้น แต่ JVM จะตรวจสอบลำดับของไบต์โค้ดที่ถูกเรียกใช้งานบ่อยครั้ง และแปลเป็นโค้ดเครื่องเพื่อเรียกใช้งานโดยตรงบนฮาร์ดแวร์ สำหรับไบต์โค้ดที่ถูกเรียกใช้งานเพียงไม่กี่ครั้ง วิธีนี้จะช่วยประหยัดเวลาในการคอมไพล์และลดความหน่วงแฝงในขั้นต้น สำหรับไบต์โค้ดที่ถูกเรียกใช้งานบ่อยครั้ง จะใช้การคอมไพล์ JIT เพื่อให้ทำงานด้วยความเร็วสูง หลังจากขั้นตอนการตีความที่ช้าในขั้นต้น นอกจากนี้ เนื่องจากโปรแกรมใช้เวลาส่วนใหญ่ในการเรียกใช้โค้ดเพียงส่วนน้อย เวลาในการคอมไพล์ที่ลดลงจึงมีความสำคัญมาก สุดท้าย ในระหว่างการตีความโค้ดในขั้นต้น สามารถรวบรวมสถิติการเรียกใช้งานก่อนการคอมไพล์ ซึ่งช่วยในการเพิ่มประสิทธิภาพได้ดียิ่งขึ้น[ 21 ]

การแลกเปลี่ยนที่ถูกต้องอาจแตกต่างกันไปตามสถานการณ์ ตัวอย่างเช่น เครื่องเสมือน Java ของ Sun มีโหมดหลักสองโหมด ได้แก่ ไคลเอนต์และเซิร์ฟเวอร์ ในโหมดไคลเอนต์ จะมีการคอมไพล์และการเพิ่มประสิทธิภาพน้อยที่สุด เพื่อลดเวลาเริ่มต้น ในโหมดเซิร์ฟเวอร์ จะมีการคอมไพล์และการเพิ่มประสิทธิภาพอย่างกว้างขวาง เพื่อเพิ่มประสิทธิภาพสูงสุดเมื่อแอปพลิเคชันทำงาน โดยยอมเสียสละเวลาเริ่มต้น คอมไพเลอร์แบบ just-in-time ของ Java อื่นๆ ใช้การวัดเวลาการทำงานของจำนวนครั้งที่เมธอดถูกเรียกใช้ร่วมกับขนาดไบต์โค้ดของเมธอดเป็นฮิวริสติกในการตัดสินใจว่าจะคอมไพล์เมื่อใด[ 22 ]ยังมีอีกตัวหนึ่งที่ใช้จำนวนครั้งที่ถูกเรียกใช้ร่วมกับการตรวจจับลูป[ 23 ]โดยทั่วไปแล้ว การคาดการณ์อย่างแม่นยำว่าควรเพิ่มประสิทธิภาพเมธอดใดในแอปพลิเคชันที่ทำงานสั้นๆ นั้นยากกว่าในแอปพลิเคชันที่ทำงานนานๆ มาก[ 24 ]

Native Image Generator (Ngen) โดยMicrosoftเป็นอีกแนวทางหนึ่งในการลดความล่าช้าเริ่มต้น[ 25 ] Ngen จะทำการคอมไพล์ล่วงหน้า (หรือ "pre-JITs") ไบต์โค้ดใน อิมเมจ Common Intermediate Languageให้เป็นโค้ดเนทีฟของเครื่อง ส่งผลให้ไม่จำเป็นต้องมีการคอมไพล์ขณะรันไทม์ . NET Framework 2.0 ที่มาพร้อมกับVisual Studio 2005 จะรัน Ngen กับไฟล์ ไลบรารีแบบไดนามิกลิงก์ (DLL) ของ Microsoft ทั้งหมดทันทีหลังจากการติดตั้ง การคอมไพล์ล่วงหน้าช่วยลดเวลาเริ่มต้น อย่างไรก็ตาม คุณภาพของโค้ดที่สร้างขึ้นอาจต่ำกว่าโค้ดที่คอมไพล์แบบ JIT ด้วยเหตุผลเดียวกันกับที่โค้ดที่คอมไพล์แบบคงที่โดยไม่มีการเพิ่มประสิทธิภาพตามโปรไฟล์ไม่สามารถดีเท่ากับโค้ดที่คอมไพล์แบบ JIT ในกรณีที่รุนแรงที่สุด นั่นคือ การขาดข้อมูลโปรไฟล์เพื่อขับเคลื่อน เช่น การแคชแบบอินไลน์[ 26 ]

นอกจากนี้ ยังมี Java เวอร์ชันที่รวมคอมไพเลอร์แบบ AOT (ahead-of-time)เข้ากับคอมไพเลอร์แบบ JIT ( Excelsior JET ) หรืออินเตอร์พรีเตอร์ ( GNU Compiler for Java ) อีกด้วย

การคอมไพล์ JIT อาจไม่สามารถบรรลุเป้าหมายได้อย่างน่าเชื่อถือ กล่าวคือ ไม่สามารถเข้าสู่สถานะคงที่ของประสิทธิภาพที่ดีขึ้นหลังจากช่วงวอร์มอัพเริ่มต้นสั้นๆ[ 27 ] [ 28 ] Barrett et al. (2017)ได้วัดไมโครเบนช์มาร์ค ที่ใช้กันอย่างแพร่หลาย 6 รายการ ซึ่งมักใช้โดยผู้พัฒนาเครื่องเสมือนเป็นเป้าหมายในการเพิ่มประสิทธิภาพ โดยทำการทดสอบซ้ำๆ ภายในการดำเนินการกระบวนการเดียว บนเครื่องเสมือน 8 เครื่องที่แตกต่างกัน [ 29 ]บนLinuxพวกเขาพบว่าการดำเนินการกระบวนการ 8.7% ถึง 9.6% ไม่สามารถเข้าสู่สถานะคงที่ของประสิทธิภาพได้ 16.7% ถึง 17.9% เข้าสู่สถานะคงที่ของ ประสิทธิภาพ ที่ลดลงหลังจากช่วงวอร์มอัพ และ 56.5% ของการจับคู่เครื่องเสมือนเฉพาะที่รันเบนช์มาร์คเฉพาะไม่สามารถเห็นประสิทธิภาพที่ไม่ลดลงในสถานะคงที่ได้อย่างสม่ำเสมอในการดำเนินการหลายครั้ง (เช่น อย่างน้อยหนึ่งการดำเนินการไม่สามารถเข้าสู่สถานะคงที่ได้ หรือเห็นประสิทธิภาพลดลงในสถานะคงที่) แม้ว่าจะเข้าสู่สถานะคงที่ที่ดีขึ้นได้ แต่บางครั้งก็ต้องใช้การวนซ้ำหลายร้อยครั้ง[ 30 ] Traini et al. (2022)มุ่งเน้นไปที่เครื่องเสมือน HotSpot แทน แต่ใช้เกณฑ์มาตรฐานที่หลากหลายกว่ามาก[ 31 ]พบว่า 10.9% ของการดำเนินการกระบวนการล้มเหลวในการบรรลุสถานะประสิทธิภาพที่คงที่ และ 43.5% ของเกณฑ์มาตรฐานไม่สามารถบรรลุสถานะที่คงที่ได้อย่างสม่ำเสมอในการดำเนินการหลายครั้ง[ 32 ]

ความปลอดภัย

การคอมไพล์แบบ JIT นั้นใช้ข้อมูลที่สามารถเรียกใช้งานได้เป็นหลัก ซึ่งก่อให้เกิดความท้าทายด้านความปลอดภัยและช่องโหว่ที่อาจเกิดขึ้นได้

การใช้งานการคอมไพล์แบบ JIT ประกอบด้วยการคอมไพล์ซอร์สโค้ดหรือไบต์โค้ดเป็นโค้ดเครื่องและเรียกใช้งาน โดยทั่วไปแล้วจะทำโดยตรงในหน่วยความจำ: คอมไพเลอร์ JIT จะส่งออกโค้ดเครื่องไปยังหน่วยความจำโดยตรงและเรียกใช้งานทันที แทนที่จะส่งออกไปยังดิสก์แล้วเรียกใช้โค้ดเป็นโปรแกรมแยกต่างหาก เหมือนกับการคอมไพล์ล่วงหน้าแบบปกติ ในสถาปัตยกรรมสมัยใหม่ สิ่งนี้ประสบปัญหาเนื่องจากการป้องกันพื้นที่ที่สามารถเรียกใช้งานได้ : หน่วยความจำใดๆ ก็ไม่สามารถเรียกใช้งานได้ มิฉะนั้นอาจมีช่องโหว่ด้านความปลอดภัย ดังนั้นหน่วยความจำต้องถูกทำเครื่องหมายว่าสามารถเรียกใช้งานได้ ด้วยเหตุผลด้านความปลอดภัย ควรทำหลังจากที่เขียนโค้ดลงในหน่วยความจำแล้ว และทำเครื่องหมายว่าอ่านอย่างเดียว เนื่องจากหน่วยความจำที่เขียนได้/เรียกใช้งานได้เป็นช่องโหว่ด้านความปลอดภัย (ดูW^X ) [ 33 ]ตัวอย่างเช่น คอมไพเลอร์ JIT ของ Firefox สำหรับJavaScriptได้นำการป้องกันนี้มาใช้ในเวอร์ชันที่เผยแพร่พร้อมกับ Firefox 46 [ 34 ]

JIT spraying คือ ช่องโหว่ด้านความปลอดภัยของคอมพิวเตอร์ประเภทหนึ่งที่ใช้การคอมไพล์แบบ JIT เพื่อ โจมตีหน่วยความจำ แบบ heap spraying : หน่วยความจำที่ได้นั้นสามารถเรียกใช้งานได้ ซึ่งจะทำให้เกิดช่องโหว่หากสามารถย้ายการเรียกใช้งานเข้าไปในหน่วยความจำแบบ heap ได้

การใช้งาน

การคอมไพล์แบบ JIT สามารถนำไปใช้กับโปรแกรมบางโปรแกรม หรือใช้สำหรับความสามารถบางอย่าง โดยเฉพาะอย่างยิ่งความสามารถแบบไดนามิก เช่นนิพจน์ปกติ (Regular Expression ) ตัวอย่างเช่น โปรแกรมแก้ไขข้อความอาจคอมไพล์นิพจน์ปกติที่ให้มาในขณะรันไทม์เป็นโค้ดเครื่องเพื่อให้จับคู่ได้เร็วขึ้น ซึ่งไม่สามารถทำได้ล่วงหน้า เนื่องจากรูปแบบจะถูกให้มาในขณะรันไทม์เท่านั้นสภาพแวดล้อมรันไทม์ สมัยใหม่หลายแห่ง อาศัยการคอมไพล์แบบ JIT เพื่อการประมวลผลโค้ดความเร็วสูง รวมถึงการใช้งานJava ส่วนใหญ่ และ . NETของMicrosoftในทำนองเดียวกัน ไลบรารีนิพจน์ปกติหลายแห่งมีการคอมไพล์นิพจน์ปกติแบบ JIT ไม่ว่าจะเป็นไบต์โค้ดหรือโค้ดเครื่อง การคอมไพล์แบบ JIT ยังใช้ในอีมูเลเตอร์บางตัว เพื่อแปลงโค้ดเครื่องจากสถาปัตยกรรม CPU หนึ่งไปยังอีกสถาปัตยกรรมหนึ่ง

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

ดูเพิ่มเติม

หมายเหตุ

  1. ^คอมไพเลอร์แบบ Ahead-of-Time (AOT) สามารถกำหนดเป้าหมายสถาปัตยกรรมไมโครเฉพาะได้เช่นกัน แต่ความแตกต่างระหว่าง AOT และ JIT ในเรื่องนี้คือเรื่องของความสามารถในการพกพา JIT สามารถสร้างโค้ดที่ปรับแต่งให้เหมาะกับ CPU ที่กำลังทำงานอยู่ในขณะรันไทม์ได้ ในขณะที่ AOT แทนที่จะปรับให้เหมาะสมกับสถาปัตยกรรมไมโครทั่วไป จะต้องทราบ CPU เป้าหมายล่วงหน้า โค้ดดังกล่าวอาจไม่เพียงแต่ทำงานได้ไม่ดีบน CPU ประเภทอื่นเท่านั้น แต่ยังอาจไม่เสถียรอีกด้วย

บรรณานุกรม

  • Barrett, Ed; Bolz-Tereick, Carl Friedrich; Killick, Rebecca ; Mount, Sarah; Tratt, Laurence (12 ตุลาคม 2017). "Virtual machine warmup blows hot and cold". Proceedings of the ACM on Programming Languages . 1 : 1–27 . arXiv : 1602.00602 . doi : 10.1145/3133876 . S2CID  1036324 .
  • Traini, Luca; Cortellessa, Vittorio; Di Pompeo, Daniele; Tucci, Michele ( 30 กันยายน 2022). "สู่การประเมินประสิทธิภาพการทำงานในสภาวะคงที่ของซอฟต์แวร์ Java อย่างมีประสิทธิภาพ: เราไปถึงจุดนั้นหรือยัง?" วิศวกรรมซอฟต์แวร์เชิงประจักษ์28 . arXiv : 2209.15369 . doi : 10.1007/s10664-022-10247-x . S2CID  252668652 .
  • Aycock, J. (มิถุนายน 2546). "ประวัติโดยย่อของระบบการผลิตแบบทันเวลาพอดี". ACM Computing Surveys . 35 (2): 97– 113. CiteSeerX  10.1.1.97.3985 . doi : 10.1145/857076.857077 . S2CID  15345671 .
  • Thompson, K. (1968). "เทคนิคการเขียนโปรแกรม: อัลกอริทึมการค้นหานิพจน์ปกติ"การสื่อสารของ ACM 11 ( 6): 419– 422. doi : 10.1145/363347.363387 . S2CID  21260384 .
  • พจนานุกรมวิทยาการคอมพิวเตอร์ออนไลน์ฟรี
  • Mozilla Nanojit ถูกเก็บถาวรเมื่อวันที่ 9 พฤษภาคม 2012 ในWayback Machine : เป็นไลบรารี ซอฟต์แวร์C++ขนาดเล็ก ที่ใช้ งาน ได้บนหลายแพลตฟอร์ม ซึ่งสร้างโค้ดเครื่องจักร มันถูกใช้เป็น JIT สำหรับเอนจิ้น JavaScript ของ Mozilla TamarinและSpiderMonkey
  • การวิเคราะห์ประสิทธิภาพการทำงานของโค้ดที่สร้างและตีความโดยใช้ VTune Performance Analyzer
ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Just-in-time_compilation&oldid=1346827793 "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ การรวบรวมแบบทันเวลาพอดี

การคอมไพล์แบบทันเวลาพอดี ( JIT ) (หรือการแปลแบบไดนามิกหรือการคอมไพล์ขณะรันไทม์ ) คือการคอมไพ ล์

ประวัติศาสตร์

โดยทั่วไปแล้วคอมไพเลอร์ JIT ตัวแรกที่เผยแพร่ถือเป็นผลงานของ John McCarthy ในภาษา LISP เมื่อปี พ.ศ.

ออกแบบ

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

ผลงาน

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