เหตุใด VMs จึงจำเป็นต้องเป็น "เครื่องซ้อน" หรือ "เครื่องลงทะเบียน" ฯลฯ


48

(นี่เป็นคำถามที่มือใหม่มาก)

ฉันได้ศึกษาเกี่ยวกับ Virtual Machines เล็กน้อยแล้ว

ปรากฎว่าส่วนมากของพวกเขาได้รับการออกแบบคล้ายกับคอมพิวเตอร์ทางกายภาพหรือทางทฤษฎี

ฉันอ่านว่า JVM เป็น 'เครื่องซ้อน' หมายความว่า (และแก้ไขให้ฉันถ้าฉันผิด) คือมันเก็บทุกอย่างไว้ใน 'หน่วยความจำชั่วคราว' บนสแต็กและทำการดำเนินการบนสแต็กนี้สำหรับ opcodes ทั้งหมด

ตัวอย่างเช่นซอร์สโค้ด2 + 3จะถูกแปลเป็น bytecode คล้ายกับ:

push 2
push 3
add

คำถามของฉันคือ:

JVMs อาจเขียนโดยใช้ C / C ++ และเช่นนั้น ถ้าเป็นเช่นนั้นทำไม JVM ไม่รันโค้ด C ต่อไปนี้: 2 + 3.. ? ฉันหมายความว่าเหตุใดจึงต้องใช้สแต็กหรือใน 'รีจิสเตอร์' VM อื่น ๆ - เหมือนในคอมพิวเตอร์จริง

CPU จริงที่มีอยู่จริงจะดูแลสิ่งเหล่านี้ทั้งหมด เหตุใดผู้เขียน VM ไม่เพียงเรียกใช้งานการแปลโดยใช้คำสั่ง 'ปกติ' ในภาษาที่ VM ตั้งโปรแกรมไว้?

ทำไม VM จึงจำเป็นต้องจำลองฮาร์ดแวร์เมื่อฮาร์ดแวร์จริงได้ทำสิ่งนี้ให้เราแล้ว?

อีกครั้งคำถามที่ newbie-ish มาก ขอบคุณสำหรับความช่วยเหลือของคุณ


5
คุณได้พิจารณาถึงสิ่งที่ไม่ใช่เครื่องเสมือนจริงหรือไม่?

5
@MichaelT คุณหมายถึงเครื่องจักรทางกายภาพ?
Aviv Cohn

แน่นอนว่า Javascript VMs ส่วนใหญ่ไม่ได้เป็นเครื่องซ้อนหรือเครื่องลงทะเบียน - V8 / IonMonkey / Chakra / ฯลฯ เป็น VM ที่ใช้งาน Javascript "VM" เป็นเพียงตัวแปลหรือ JIT ซึ่งสามารถใช้ภาษาใดก็ได้ที่ผู้ออกแบบต้องการ
Billy ONeal

@BillyONeal ตัวอย่างเช่นถ้าฉันเขียน VM สำหรับบางภาษาและฉันเขียนใน C: VM จะแยกวิเคราะห์บรรทัด bytcode 'print "hi"' และดำเนินการprintf("hi");: นี่ถือว่าเป็น VM หรือไม่ มันไม่มี 'stack' หรือ 'register' และหรืออะไรก็ตาม
Aviv Cohn

@Prog: ใช่แล้วถูกต้อง
Billy ONeal

คำตอบ:


51

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

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

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

แต่เพื่อให้ตรงประเด็นนี่คือเหตุผลบางประการในการสร้าง VM (เช่นเดียวกับสิ่งที่กำหนดเป้าหมายโดยคอมไพเลอร์ bytecode) หรือการลงทะเบียน สแต็คและเครื่องลงทะเบียนง่ายมาก มีลำดับของคำสั่งบางสถานะและซีแมนทิกส์สำหรับแต่ละคำสั่ง (สถานะฟังก์ชั่น -> รัฐ) ไม่มีการลดทรีแบบซับซ้อนไม่มีตัวดำเนินการที่สำคัญกว่า การแยกวิเคราะห์และดำเนินการเป็นเรื่องง่ายมากเพราะเป็นภาษาที่น้อยที่สุด (มีการรวบรวมน้ำตาลประโยค) และออกแบบให้อ่านด้วยเครื่องแทนที่จะอ่านโดยมนุษย์

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

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


ดังนั้นสิ่งที่คุณกำลังพูดคือการรวบรวมทุกอย่างเพื่อเป็นคำสั่งในสแต็ก (เช่นSystem.out.println("hi");รวบรวมคำสั่งบางอย่างในสแต็กint a = 7จะถูกคอมไพล์ไปยังคำสั่งบนสแต็ก ฯลฯ ) ทำให้การดำเนินโปรแกรมง่ายขึ้นและมีประสิทธิภาพมากขึ้น?
Aviv Cohn

2
@Prog โดยทั่วไปใช่ แต่ไม่เพียงแค่การประมวลผลเท่านั้น แต่ยังทำการวิเคราะห์ด้วย ทุกอย่างที่ทำโดยทางโปรแกรม

แต่ฉันก็ยังไม่เข้าใจว่าทำไมจะรวบรวมไป2 + 3 ขั้นตอนในตอนท้ายจะถูกดำเนินการโดย JVM อยู่แล้วโดยใช้รหัส ไม่มีวิธีอื่นใดที่โปรแกรมเมอร์ของ JVM จะทำเช่นนี้ ทำไมไม่คอมไพล์มันและให้ JVM เพียงแค่รันโค้ด C (สมมติว่ามันเขียนเป็น C) ทันที? push 2 push 3 addadd2 + 32 + 32 + 3
Aviv Cohn

@Prog ผู้เขียน JVM ไม่สามารถเขียน2 + 3ในซอร์สโค้ด JVM ได้เนื่องจาก JVM ต้องทำงานกับโปรแกรมใด ๆ ที่ดำเนินการตามลำดับใด ๆ การสร้างซอร์สโค้ด C และการชะลอการใช้งาน C เพียงแค่ส่งปัญหาเดียวกันไปสู่การใช้งาน C (และไม่สามารถทำได้อย่างง่ายดาย จะต้องมีโครงสร้างข้อมูลบางอย่างที่อธิบายโปรแกรมเพื่อให้สามารถตีความและรวบรวม JIT และ "ซอร์สโค้ดที่มนุษย์สามารถอ่านได้" เป็นตัวเลือกที่น่ากลัวของโครงสร้างข้อมูลด้วยเหตุผลที่กล่าวถึงข้างต้น

7
@Prog ดูเหมือนว่าคุณจะมุ่งเน้นไปที่กรณีเฉพาะของ 2 + 3 แล้วคุณa + bล่ะ? จากนั้นค่าที่จะเพิ่มไม่ได้มาจากi.argument{1,2}พวกเขาจะถูกโหลดจากตัวแปรท้องถิ่น เกี่ยวกับfrobnicate(x[i]) + (Foo.bar() * 2)อะไร การใช้การออกแบบนี้มีaddการดำเนินการเพียงครั้งเดียว(สำหรับint) และทำงานได้อย่างเป็นอิสระจากวิธีการคำนวณที่เพิ่มเข้ามา นอกจากนี้คำสั่งที่เพิ่มเฉพาะตัวอักษรจำนวนเต็มจะไม่มีจุดหมาย: ผลลัพธ์ของมันอาจคำนวณได้ล่วงหน้าเช่นกัน (แทนที่จะadd(2,3)เป็นควรเป็นpush(5))

20

คำตอบนี้มุ่งเน้นไปที่ JVM แต่ที่จริงแล้วมันใช้กับ VM ใด ๆ

ทำไม VM จึงจำเป็นต้องจำลองฮาร์ดแวร์เมื่อฮาร์ดแวร์จริงได้ทำสิ่งนี้ให้เราแล้ว?

แต่มันทำให้ VM ง่ายและพกพาได้มาก: VM ที่เลียนแบบฮาร์ดแวร์สามารถใช้โมเดลการคำนวณเดียวกันกับ CPU ของฮาร์ดแวร์ใด ๆ

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

หากคุณมีเป้าหมายเช่นนี้เป็นที่พึงปรารถนาที่ VM จะทำงานใกล้เคียงกับเครื่องจักรจริงเท่าที่จะทำได้เพราะการแปลรหัสเครื่องจริงจะง่ายขึ้นและเร็วขึ้น เมื่อคุณมี opcodes ของ VM ในทางทฤษฎีสิ่งที่คุณต้องทำคือแปลเป็น opcodes ของ CPU ที่โปรแกรมทำงานจริง ในทางปฏิบัติมันไม่ง่ายอย่างนั้น

ฉันหมายความว่าเหตุใดจึงต้องใช้สแต็กหรือใน 'รีจิสเตอร์' VM อื่น ๆ - เหมือนในคอมพิวเตอร์จริง

การใช้โมเดลเครื่องเสมือนแบบกองซ้อนมีข้อได้เปรียบที่สามารถถ่ายโอนไปยังทั้งเครื่องบันทึกและเครื่องซ้อนได้อย่างง่ายดายในขณะที่ตรงกันข้ามไม่จำเป็นต้องเป็นจริง VM ที่ใช้รีจิสเตอร์จะต้องทำการตั้งสมมติฐานเกี่ยวกับจำนวนของรีจิสเตอร์ขนาดของรีจิสเตอร์และอื่น ๆ ด้วยเครื่องสแต็คไม่จำเป็นต้องใช้สมมติฐานดังกล่าว

CPU จริงที่มีอยู่จริงจะดูแลสิ่งเหล่านี้ทั้งหมด เหตุใดผู้เขียน VM ไม่เพียงเรียกใช้งานการแปลโดยใช้คำสั่ง 'ปกติ' ในภาษาที่ VM ตั้งโปรแกรมไว้?

นั่นคือสิ่งที่ VMs ทำเช่นนั้นพวกเขาตีความ bytecode แม้แต่ JVM ก็ทำเช่นนั้นอย่างน้อยก็ก่อนที่ JIT (ทันเวลา) จะเตะใน: มันตีความรหัสไบต์และประมวลผลคำสั่งในภาษาที่ JVM เขียน (โดยทั่วไปคือ C หรือ C ++ แต่มีแม้แต่ฉบับเดียวที่เขียน ใน JavaScript, Doppio ) อย่างไรก็ตามโปรดทราบว่าแม้ข้อความดังกล่าวจะถูกแปลเป็นโค้ดเครื่องโดยคอมไพเลอร์และจริงๆแล้วก็ดูคล้ายกับสิ่งที่คอมไพเลอร์ Java สร้างขึ้น - นั่นคือพวกเขาใช้รีจิสเตอร์และสแต็กเพื่อทำงานของพวกเขา โปรดสังเกตว่าการใช้ภาษา "ตีความ" เทียบกับ "รวบรวม" จะค่อนข้างพร่ามัวในตอนนี้


แน่นอนว่าสิ่งใดก็ตามที่สามารถนำไปใช้ในซอฟต์แวร์สามารถนำไปใช้ในฮาร์ดแวร์ นอกจากนี้ JVM ปัจจุบัน (ฮอตสปอต) เป็นคอมไพเลอร์ JIT - มันไม่ได้ดำเนินการคำสั่งในภาษาที่ JVM เขียนถ้ามันทำเช่นนั้น Java จะทำงานได้ชะมัดและจะอยู่ใกล้กับแพลตฟอร์มที่เป็นอยู่ในปัจจุบัน . (ยิ่งไปกว่านั้นการใช้งานจาวาสคริปต์ส่วนใหญ่จะเร็วขึ้น)
Billy ONeal

2
@BillyONeal "แทนที่จะรวบรวมวิธีด้วยวิธีการทันเวลา Java HotSpot VM จะรันโปรแกรมโดยใช้ล่ามทันทีและวิเคราะห์รหัสในขณะที่มันทำงานเพื่อตรวจหาฮอตสปอตที่สำคัญในโปรแกรมจากนั้นจะเน้นความสนใจของ เครื่องมือเพิ่มประสิทธิภาพรหัสพื้นเมืองระดับโลกในจุดที่น่าสนใจ "อ้างจากoracle.com/technetwork/java/whitepaper-135217.html#2ส่วน" การตรวจจับจุดร้อน "
miraculixx

ใช่. "Native code optimizer" == การรวบรวม JIT มีเฟสตัวแปลสำหรับโค้ดซึ่งดูเหมือนจะไม่ "ฮอต" เพื่อหลีกเลี่ยงการใช้ JIT กับสิ่งที่ไม่ค่อยได้ใช้ แต่นั่นไม่ได้หมายความว่าจะไม่มีการทำ JITing เลย
Billy ONeal

ขอบคุณสำหรับคำตอบ. สิ่งที่ฉันรวบรวมได้จากคำตอบของคุณคือเหตุผลที่เลียนแบบฮาร์ดแวร์ใน VM (หรือที่รู้จักกับ 'สแต็ค' หรือ 'รีจิสเตอร์' เป็นต้น) เพราะมันทำให้ง่ายต่อการคอมไพล์ bytecode หรือซอร์สโค้ดกับรหัสเครื่องจริงของ CPU จริง อย่างไรก็ตามนอกเหนือจากนั้น - มีอะไรที่จะได้รับจากการเลียนแบบฮาร์ดแวร์ใน VM หรือไม่? ฉันยังไม่เข้าใจว่าทำไมคนออกแบบ VM จะคิดในแง่ของ 'stack machine' หรือ 'register machine' เป็นต้นเมื่อจริง ๆ แล้วเรากำลังพูดถึงซอฟต์แวร์ ฉันพลาดอะไรไปรึเปล่า?
Aviv Cohn

@Prog ตกลงคุณมีภาษาการเขียนโปรแกรมพูด X. คุณจะรันโปรแกรมอย่างไร คุณสามารถแปลความหมายแหล่งที่มาหรือรวบรวมเป็นรหัสเครื่องหรือรวบรวมเป็นรหัสกลางบางอย่าง ตอนนี้คุณมีภาษาโปรแกรมอีกภาษาหนึ่ง Y และต้องการนำมาใช้โดยใช้ X หากการใช้งานทั้งสองเป็นล่ามคุณจะมีล่ามของ Y ที่ทำงานบนล่ามของ X และสิ่งนี้จะช้ามาก
18446744073709551615

11

เหตุใด VMs จึงจำเป็นต้องเป็น "เครื่องซ้อน" หรือ "เครื่องลงทะเบียน" ฯลฯ

พวกเขาไม่ได้. หากคุณต้องการเครื่องเสมือนอาจเป็นอะไรก็ได้

เครื่องเสมือนที่มีอยู่ได้ปรากฏขึ้นเพื่อแก้ไขสถานการณ์เช่น: ความคิดที่ยอดเยี่ยมจริงๆมาถึงหัวของฉันฉันได้คิดค้นภาษาการเขียนโปรแกรมใหม่! แต่ฉันต้องสร้างรหัส (มันเป็นงานที่น่าเบื่อ!) แต่ฉันไม่ต้องการสร้างรหัส i8086 เพราะมันน่าเกลียดและฉันไม่ต้องการสร้างรหัส 68k เพราะทุกคนใช้ Intel นอกจากนี้ยังมี VAX แต่ฉันไม่มี VAX ใด ๆ ไม่ว่าจะเป็นคอมพิวเตอร์หรือหนังสือ VAX ดังนั้นฉันจะสร้างรหัสสำหรับโปรเซสเซอร์บางตัวที่ไม่มีอยู่จริงและใช้โปรเซสเซอร์นั้นในซอฟต์แวร์ สเป็คของ VM นั้นจะทำให้บทในวิทยานิพนธ์ของฉัน ในทางทฤษฎีแล้วมันจะเป็นไปได้ที่จะคอมไพล์มันให้เป็นรหัสเนทีฟของโปรเซสเซอร์ใด ๆ แต่นั่นจะไม่ใช่ฉัน

ในทางกลับกันสัญกรณ์เช่น "2 + 3" อาจจะไม่ถูกใช้โดย VM ในอนาคตอันใกล้เพราะมันหมายถึงการทำการเปลี่ยนแปลงมากมายก่อนที่บางสิ่งอาจถูกดำเนินการ


ขอบคุณสำหรับคำตอบ. ดังนั้นสิ่งที่ฉันรวบรวมได้จากคำตอบของคุณก็คือแรงจูงใจในการออกแบบ VM ที่เลียนแบบซีพียูทางกายภาพเพราะมันทำให้ง่ายต่อการติดตั้งคอมไพเลอร์ในภายหลังเพื่อคอมไพล์รหัสเครื่องจริง แต่นอกเหนือจากนั้น - มีข้อได้เปรียบอะไรบ้างในการออกแบบ VM ในแง่ของ 'stack machine' หรือ 'register machine' ฯลฯ ?
Aviv Cohn

1
รีจิสเตอร์ต้องการอัลกอริธึมการจัดสรรรีจิสเตอร์ที่ต้องการทั้งทฤษฎีและการดีบัก เครื่องสแต็ค (โดยเฉพาะหนึ่งตัวถูกดำเนินการศูนย์) สามารถวางข้อมูลบนสแต็ก OTOH ฮาร์ดแวร์มักใช้รีจิสเตอร์ในปริมาณที่ จำกัด แทนที่จะใช้สแต็กขนาดแปรผัน ดังนั้นซอฟต์แวร์จึงมีความง่ายในการลงทะเบียนจึงง่ายกว่าสำหรับฮาร์ดแวร์และอาจเร็วกว่าเล็กน้อย
18446744073709551615

-2

เพื่อตอบคำถามจริงที่ถูกถาม คำว่า "virtual machine" หมายถึงซอฟต์แวร์ / ฮาร์ดแวร์ทั้งหมดได้รับการจำลอง / จำลอง หากคุณใช้ซอฟต์แวร์ / ฮาร์ดแวร์พื้นฐานเพื่อดำเนินการตามคำแนะนำแล้วคุณไม่มี VM คุณมีคอมไพเลอร์ / ล่าม


นี่เป็นเพียงความคิดเห็นของคุณหรือคุณสามารถสำรองข้อมูลอย่างใด
ริ้น

@Kyrelel ที่ไม่เป็นความจริง ฮาร์ดแวร์ "ALL" ถูกจำลองในระบบ "หรือ" เต็ม "VM VMs ทั้งหมดไม่เต็ม ตัวอย่างเช่นเลเยอร์ BSD VM มีชื่อว่า "virtual machine" แม้ว่าจะไม่ได้จำลองฮาร์ดแวร์
Netch

ฉันไม่คิดว่าคำถามจำเป็นต้องเกี่ยวกับคำศัพท์ แต่ทำไมเครื่องเสมือนใช้ฟังก์ชันการทำงานที่ฮาร์ดแวร์จริงดูเหมือนจะจัดการแล้ว
Ryan
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.