Java Virtual Machine และ CLR


140

ตามประเภทคำถามที่เรียกว่าความแตกต่างระหว่าง MSIL และ Java bytecode อะไรคือความแตกต่าง (หลัก) หรือความคล้ายคลึงกันในการทำงานของ Java Virtual Machine กับวิธีการ. NET Framework Common Language Runtime (CLR) ใช้งานได้?

นอกจากนี้ยังเป็น กรอบงาน. NET CLR เป็น "เครื่องเสมือน" หรือไม่มีคุณลักษณะของเครื่องเสมือนหรือไม่


ถ้าคุณเปรียบเทียบสิ่งที่ชอบและชอบคุณควรตั้งคำถามใหม่เป็นความแตกต่างระหว่าง VM และ CLR (Common Language Runtime) ซึ่งเป็นแอนะล็อกโดยตรงกับ VM
cletus

คำตอบ:


278

มีความคล้ายคลึงกันมากระหว่างการติดตั้งใช้งานทั้งสอง (และในความคิดของฉัน: ใช่พวกเขาทั้งคู่เป็น "เครื่องเสมือน")

ประการหนึ่งพวกเขาเป็นทั้ง VM แบบกองซ้อนโดยไม่มีแนวคิดเรื่อง "การลงทะเบียน" เหมือนกับที่เราเคยเห็นในซีพียูสมัยใหม่เช่น x86 หรือ PowerPC การประเมินผลของนิพจน์ทั้งหมด ((1 + 1) / 2) ดำเนินการโดยการกดโอเปอแรนต์ลงใน "สแต็ก" และจากนั้นเปิดโอเปอเรเตอร์เหล่านั้นออกจากสแต็กเมื่อใดก็ตามที่คำสั่ง (เพิ่มหาร ฯลฯ ) แต่ละคำสั่งจะส่งผลลัพธ์กลับไปที่สแต็ก

เป็นวิธีที่สะดวกในการติดตั้งเครื่องเสมือนเพราะ CPU ทุกตัวในโลกมีจำนวนมาก แต่จำนวนของรีจิสเตอร์มักแตกต่างกัน (และรีจิสเตอร์บางตัวมีจุดประสงค์พิเศษและแต่ละคำสั่งคาดว่าจะถูกดำเนินการในรีจิสเตอร์ต่าง ๆ ฯลฯ )

ดังนั้นหากคุณกำลังจะสร้างแบบจำลองเครื่องนามธรรมรูปแบบสแต็กตามล้วนเป็นวิธีที่ดีที่จะไป

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

ดังนั้นฉันคิดว่าเป็นหนึ่งใน commonalities ที่ใหญ่ที่สุดระหว่าง CLR และ JVM

สำหรับความแตกต่าง ...

ความแตกต่างที่น่าสนใจอย่างหนึ่งระหว่างการนำไปใช้งานสองอย่างคือ CLR มีคำแนะนำสำหรับการสร้างประเภททั่วไป ดังนั้น ณ รันไทม์ CLR จะพิจารณา List <int> เป็นประเภทที่แตกต่างอย่างสิ้นเชิงจาก List <String>

ภายใต้หน้าปกมันใช้ MSIL เดียวกันสำหรับความเชี่ยวชาญเฉพาะประเภทการอ้างอิงทั้งหมด (ดังนั้นรายการ <String> จะใช้การดำเนินการเช่นเดียวกับรายการ <Object> ที่มีการคาสต์ประเภทต่าง ๆ ที่ขอบเขต API) แต่การใช้ค่าแต่ละประเภทนั้น การใช้งานที่ไม่ซ้ำกันของตัวเอง (รายการ <int> สร้างรหัสที่แตกต่างอย่างสิ้นเชิงจากรายการ <double>)

ใน Java ประเภททั่วไปเป็นเคล็ดลับเรียบเรียง JVM ไม่มีความเห็นว่าคลาสใดมีอาร์กิวเมนต์ชนิดและไม่สามารถดำเนินการทางพารามิเตอร์เฉพาะในเวลารันไทม์

จากมุมมองที่ใช้งานได้จริงนั่นหมายความว่าคุณไม่สามารถโอเวอร์โหลดเมธอด Java ในประเภททั่วไปได้ คุณไม่สามารถมีสองวิธีที่แตกต่างกันโดยใช้ชื่อเดียวกันต่างกันเพียงว่าพวกเขายอมรับ List <String> หรือ List <Date> แน่นอนเนื่องจาก CLR รู้เกี่ยวกับประเภทพารามิเตอร์จึงไม่มีวิธีการจัดการกับปัญหาที่เกิดขึ้นกับความเชี่ยวชาญประเภททั่วไป

ในแต่ละวันนั่นคือความแตกต่างที่ฉันสังเกตเห็นมากที่สุดระหว่าง CLR และ JVM

ความแตกต่างที่สำคัญอื่น ๆ ได้แก่ :

  • CLR มีการปิด (ดำเนินการในฐานะตัวแทน C #) JVM รองรับการปิดเฉพาะตั้งแต่ Java 8

  • CLR มี coroutines (นำไปใช้กับคำหลัก C # 'yield') JVM ไม่ได้

  • CLR ช่วยให้รหัสผู้ใช้สามารถกำหนดประเภทของค่าใหม่ (structs) ในขณะที่ JVM มีการจัดเก็บประเภทค่าคงที่ (ไบต์สั้น, int, ยาว, ลอย, สอง, ถ่าน, บูลีน) และอนุญาตให้ผู้ใช้กำหนดการอ้างอิงใหม่เท่านั้น ประเภท (คลาส)

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

  • หน่วยที่ใหญ่ที่สุดของรหัสใน JVM นั้นเป็น 'แพ็คเกจ' ที่เห็นได้จากคำสำคัญ 'ที่ได้รับการปกป้อง' หรือ JAR (เช่น Java ARchive) เป็นหลักฐานโดยสามารถระบุขวดใน classpath และให้มันเหมือนโฟลเดอร์ ของรหัส ใน CLR คลาสจะถูกรวมเข้าใน 'แอสเซมบลี' และ CLR จัดเตรียมตรรกะสำหรับเหตุผลเกี่ยวกับและจัดการแอสเซมบลี (ซึ่งถูกโหลดลงใน "AppDomains" ให้แซนด์บ็อกซ์ระดับย่อยสำหรับการจัดสรรหน่วยความจำ

  • รูปแบบ CLR bytecode (ประกอบด้วยคำสั่ง MSIL และข้อมูลเมตา) มีประเภทคำสั่งน้อยกว่า JVM ใน JVM ทุกการดำเนินการที่ไม่ซ้ำกัน (เพิ่มสองค่า int เพิ่มสองค่าลอย ฯลฯ ) มีคำสั่งที่เป็นเอกลักษณ์ของตัวเอง ใน CLR คำสั่ง MSIL ทั้งหมดคือ polymorphic (เพิ่มสองค่า) และคอมไพเลอร์ JIT มีหน้าที่กำหนดประเภทของตัวถูกดำเนินการและสร้างรหัสเครื่องที่เหมาะสม ฉันไม่ทราบว่าเป็นกลยุทธ์ที่ดีกว่าแม้ว่า ทั้งสองมีการแลกเปลี่ยน คอมไพเลอร์ HotSpot JIT สำหรับ JVM สามารถใช้กลไกการสร้างรหัสที่ง่ายขึ้น (ไม่จำเป็นต้องกำหนดชนิดของตัวถูกดำเนินการเพราะมันถูกเข้ารหัสในคำสั่งแล้ว) แต่นั่นหมายความว่ามันต้องการรูปแบบไบต์ที่ซับซ้อนมากขึ้น ด้วยคำแนะนำเพิ่มเติมประเภท

ฉันใช้ Java (และชื่นชม JVM) มาประมาณสิบปีแล้ว

แต่ในความคิดของฉัน CLR คือตอนนี้การใช้งานที่เหนือกว่าในเกือบทุกทาง


73
การปิดและเครื่องกำเนิดไฟฟ้าจะถูกนำมาใช้ในระดับภาษาและจะแสดงเป็นคลาสในระดับ CLR
Curt Hagenlocher

2
แล้วความแตกต่างในวิธีจัดการกับกองคืออะไร CLR ขึ้นอยู่กับ OS / โฮสต์ proc ในขณะที่ JVM จัดการหน่วยความจำฮีปมากขึ้นหรือน้อยลงอย่างสมบูรณ์
Kelly S. French

6
ข้อแตกต่างที่สำคัญคือความแตกต่างระหว่างการคอมไพล์แบบทันเวลา (CLR) และการปรับให้เหมาะสมแบบปรับใน (Oracle / Sun) JVM
Edwin Dalorzo

1
สล็อตโลคัลตัวแปรของ Java ทำหน้าที่เหมือนกับรีจิสเตอร์ แต่มันเป็นสิ่งที่สงสัยอยู่แล้วตั้งแต่ JIT เปลี่ยนสล็อตท้องถิ่นและสแต็คเป็นการลงทะเบียนจริง
พลวง

1
@kuhajeyan นั่นเป็นเพราะเมื่อ CLR ถูกนำมาใช้ JVM มีอายุ 10 ปี นั่นเป็นเวลานานในด้านไอที เมื่อ JVM เข้ามาในปี 1993 ไม่มีคู่แข่งที่จริงจังสำหรับ CLR (2003) มี JVM ที่เป็นผู้ใหญ่และมั่นคงพร้อมตั้งหลักที่แข็งแกร่งในอุตสาหกรรม
เพื่อนง่าย

25

คำถามแรกของคุณคือการเปรียบเทียบ JVM กับ. NET Framework ฉันคิดว่าคุณตั้งใจจะเปรียบเทียบกับ CLR แทน ถ้าเป็นเช่นนั้นฉันคิดว่าคุณสามารถเขียนหนังสือเล่มเล็ก ๆ เกี่ยวกับเรื่องนี้ ( แก้ไข:ดูเหมือนว่า Benji มี :-) อยู่แล้ว

ความแตกต่างที่สำคัญอย่างหนึ่งคือ CLR ได้รับการออกแบบให้เป็นสถาปัตยกรรมที่เป็นกลางทางภาษาซึ่งแตกต่างจาก JVM

ข้อแตกต่างที่สำคัญอีกประการหนึ่งคือ CLR ได้รับการออกแบบมาโดยเฉพาะเพื่อให้สามารถใช้งานร่วมกันได้ในระดับสูงด้วยรหัสเนทีฟ ซึ่งหมายความว่า CLR จะต้องจัดการความน่าเชื่อถือและความปลอดภัยเมื่อหน่วยความจำดั้งเดิมมีการเข้าถึงและแก้ไขและยังจัดการ marshallingระหว่างโครงสร้างข้อมูลที่ใช้ CLR และโครงสร้างข้อมูลดั้งเดิม

เพื่อตอบคำถามที่สองของคุณคำว่า“ virtual machine” เป็นคำศัพท์ที่เก่ากว่าจากโลกฮาร์ดแวร์ (เช่น virtualisation ของ IBM ใน 360 ในทศวรรษ 1960) ที่ใช้หมายถึงการจำลองซอฟต์แวร์ / ฮาร์ดแวร์ของเครื่องต้นแบบเพื่อให้ได้ชนิดเดียวกัน สิ่งที่ VMware ทำ

CLR มักถูกเรียกว่า "เอ็นจิ้นการทำงาน" ในบริบทนี้เป็นการดำเนินการของเครื่อง IL ที่อยู่บน x86 นี่เป็นสิ่งที่ JVM ทำเช่นกันแม้ว่าคุณจะสามารถยืนยันได้ว่ามีความแตกต่างที่สำคัญระหว่างไบต์โพลิมอร์ฟิคของ CLR และโพรโทคอลที่พิมพ์โดย JVM

ดังนั้นคำตอบสำหรับคำถามที่สองของคุณคือ "ไม่" แต่จริง ๆ แล้วลงไปที่วิธีที่คุณกำหนดคำสองคำนี้

แก้ไข:อีกหนึ่งความแตกต่างระหว่าง JVM และ CLR คือ JVM (รุ่น 6) ลังเลที่จะปล่อยหน่วยความจำที่จัดสรรกลับไปยังระบบปฏิบัติการแม้ว่าจะสามารถทำได้ก็ตาม

ตัวอย่างเช่นสมมติว่ากระบวนการ JVM เริ่มต้นและจัดสรรหน่วยความจำ 25 MB จากระบบปฏิบัติการในตอนแรก จากนั้นรหัสแอปจะพยายามจัดสรรที่ต้องการเพิ่มอีก 50 MB JVM จะจัดสรรอีก 50 MB จากระบบปฏิบัติการ เมื่อโค้ดแอปพลิเคชันหยุดใช้หน่วยความจำนั้นจะเป็นการรวบรวมขยะและขนาดฮีป JVM จะลดลง อย่างไรก็ตาม JVM จะเพิ่มหน่วยความจำระบบปฏิบัติการที่จัดสรรให้ภายใต้สถานการณ์เฉพาะบางอย่างเท่านั้น มิฉะนั้นสำหรับส่วนที่เหลือของอายุการใช้งานของกระบวนการนั้นหน่วยความจำจะยังคงถูกจัดสรรไว้

ในทางกลับกัน CLR จะปล่อยหน่วยความจำที่จัดสรรกลับไปยังระบบปฏิบัติการหากไม่ต้องการใช้อีกต่อไป ในตัวอย่างข้างต้น CLR จะปล่อยหน่วยความจำทันทีเมื่อฮีปลดลง


2
มันไม่สมบูรณ์ที่ JVM จะไม่จัดสรรหน่วยความจำให้ฟรี ดูคำตอบของฉันสำหรับคำถามนี้เพื่อพิสูจน์: stackoverflow.com/questions/366658/…
Michael Borgwardt

ฉันเห็น JVM ส่งคืนหน่วยความจำกลับไปเป็น Windows
Steve Kuo

ฉันเปลี่ยนคำตอบเพื่อบอกว่า JVM 6 ลังเลที่จะปล่อยหน่วยความจำพร้อมลิงก์ไปยังคำตอบของ Ran และ Michael ฉันไม่เคยเห็นพฤติกรรมนี้กับ JVM 5 ดังนั้นบางทีเวอร์ชันนั้นอาจลังเลมากกว่า
HTTP 410

คุณช่วยอธิบายวิธีที่ JVM จัดการฮีปในขณะที่ CLR อาศัยกระบวนการพาเรนต์ได้อย่างไร ตัวอย่างที่ฉันใช้คือ JVM มี runtime args สำหรับขนาด heap สูงสุดในขณะที่สภาพแวดล้อม CLR เริ่มต้นไม่ได้ แม้ว่าจะเป็นจริงแล้วแอป CLR ที่โฮสต์ภายใต้ IIS สามารถกำหนดค่า IIS ให้ จำกัด หน่วยความจำได้นั่นหมายความว่ารวมถึง IIS ในคำจำกัดความของเครื่องเสมือน
Kelly S. French

@ Steve Kuo ใช่ฉันก็เคยเห็นเช่นกัน ปกติระหว่าง 17.00 น. ถึง 18.00 น.
เพื่อนง่าย

11

CLR และ JVM เป็นทั้งเครื่องเสมือน

.NET Framework และ Java Runtime Environment เป็นชุดของ VM ที่เกี่ยวข้องและไลบรารีของพวกเขา หากไม่มีไลบรารี่ VMs ก็ไม่มีประโยชน์อะไรเลย


11

เฉพาะเจาะจงมากขึ้นเกี่ยวกับความแตกต่างสามารถพบได้จากแหล่งข้อมูลทางวิชาการและเอกชนต่างๆ เมื่อตัวอย่างที่ดีคือทางเลือก CLR ออกแบบ

ตัวอย่างที่เฉพาะเจาะจง ได้แก่ :

  • opperands ระดับต่ำบางตัวถูกพิมพ์เช่น "add two ints" โดยที่ CLR ใช้ตัวถูกดำเนินการแบบ polymorphic (เช่น fadd / iadd / ladd vs เพิ่ม)
  • ขณะนี้ JVM ทำโปรไฟล์รันไทม์และการปรับแต่งให้เหมาะสมยิ่งขึ้น (เช่น Hotspot) ปัจจุบัน CLR ทำการปรับแต่ง JIT แต่ไม่ใช่การเพิ่มประสิทธิภาพรันไทม์ (เช่นแทนที่รหัสในขณะที่คุณกำลังทำงาน)
  • CLR ไม่ได้ใช้วิธีเสมือนแบบอินไลน์ JVM ทำ ...
  • สนับสนุนประเภทค่าใน CLR ที่นอกเหนือจาก "พื้นฐาน"

-11

ไม่ใช่เครื่องเสมือนเฟรมเวิร์ก. net จะรวบรวมแอสเซมบลีเป็นไบนารี่ดั้งเดิมในขณะที่ทำการรันครั้งแรก:

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

สภาพแวดล้อมรันไทม์ที่ทันสมัยหลายแห่งเช่น. NET Framework ของ Microsoft การใช้งานจาวาส่วนใหญ่และ Actionscript 3 ล่าสุดใช้การรวบรวม JIT สำหรับการเรียกใช้โค้ดความเร็วสูง

ที่มา: http://en.wikipedia.org/wiki/Just-in-time_compilation

การเพิ่ม. NET framework ประกอบด้วยเครื่องเสมือนเช่นเดียวกับ Java


10
เพียงเพราะเครื่องเสมือนใช้ประโยชน์จาก JIT สำหรับการเพิ่มประสิทธิภาพไม่ได้หมายความว่ามันไม่ใช่เครื่องเสมือนอีกต่อไป เมื่อโปรแกรมเมอร์คอมไพล์เขาคอมไพล์ไปที่เวอร์ชวลแมชชีน, ออกจากการใช้งานเพื่อดำเนินการตามที่เห็นสมควร
Allain Lalonde
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.