दोनों कार्यान्वयन (और मेरी राय में: हाँ, वे दोनों "वर्चुअल मशीन") में बहुत समानताएँ हैं।
एक बात के लिए, वे दोनों स्टैम्प-आधारित वीएम हैं, "रजिस्टरों" की कोई धारणा नहीं है जैसे कि हम एक आधुनिक सीपीयू जैसे x86 या पावरपीसी में देखने के आदी हैं। सभी अभिव्यक्तियों का मूल्यांकन ((1 + 1) / 2) "स्टैक" पर ऑपरेंड को धक्का देकर किया जाता है और फिर जब भी कोई निर्देश (ऐड, डिवाइड, आदि) उन ऑपरेंड को खपाने की आवश्यकता होती है, तो उन ऑपरेंड को पॉपप करके उन ऑपरेंड का उपभोग करने की आवश्यकता होती है। प्रत्येक निर्देश इसके परिणामों को स्टैक पर वापस धकेलता है।
यह एक वर्चुअल मशीन को लागू करने का एक सुविधाजनक तरीका है, क्योंकि दुनिया में हर सीपीयू में एक स्टैक होता है, लेकिन रजिस्टरों की संख्या अक्सर अलग होती है (और कुछ रजिस्टर विशेष उद्देश्य वाले होते हैं, और प्रत्येक निर्देश विभिन्न रजिस्टरों में इसके ऑपरेंड की उम्मीद करता है, आदि) )।
इसलिए, यदि आप एक अमूर्त मशीन का मॉडल बनाने जा रहे हैं, तो विशुद्ध रूप से स्टैक-आधारित मॉडल एक बहुत अच्छा तरीका है।
बेशक, असली मशीनें इस तरह से काम नहीं करती हैं। तो JIT संकलक, बायटेकोड संचालन के "एनरगेटिंग" को करने के लिए ज़िम्मेदार है, अनिवार्य रूप से जब भी संभव हो ऑपरेशंस और परिणाम शामिल करने के लिए वास्तविक सीपीयू रजिस्टरों का निर्धारण करता है।
इसलिए, मुझे लगता है कि सीएलआर और जेवीएम के बीच सबसे बड़ी समानता है।
अंतर के रूप में ...
दो कार्यान्वयन के बीच एक दिलचस्प अंतर यह है कि सीएलआर में सामान्य प्रकार बनाने के लिए निर्देश शामिल हैं, और फिर उन प्रकारों के लिए पैरामीट्रिक विशेषज्ञताओं को लागू करने के लिए। इसलिए, क्रम में, CLR एक सूची <int> को सूची <स्ट्रिंग> से पूरी तरह से अलग प्रकार मानता है।
कवर के तहत, यह सभी संदर्भ-प्रकार की विशेषज्ञता के लिए एक ही एमएसआईएल का उपयोग करता है (इसलिए एक सूची <स्ट्रिंग> एक ही कार्यान्वयन का उपयोग सूची <ऑब्जेक्ट>, एपीआई सीमाओं पर विभिन्न प्रकार के कलाकारों के साथ करता है), लेकिन प्रत्येक मूल्य-प्रकार का उपयोग करता है इसका अपना अनूठा कार्यान्वयन (सूची <int> सूची <डबल> से पूरी तरह से अलग कोड उत्पन्न करता है)।
जावा में, जेनेरिक प्रकार एक शुद्ध संकलक चाल है। जेवीएम की कोई धारणा नहीं है कि किस वर्ग के पास तर्क-वितर्क हैं, और यह रनटाइम में पैरामीट्रिक विशेषज्ञता का प्रदर्शन करने में असमर्थ है।
व्यावहारिक दृष्टिकोण से, इसका मतलब है कि आप जेनेरिक प्रकारों पर जावा विधियों को अधिभार नहीं दे सकते। आपके पास दो अलग-अलग विधियाँ नहीं हो सकती हैं, एक ही नाम के साथ, केवल इस बात पर भिन्न है कि वे एक सूची <स्ट्रिंग> या सूची <दिनांक> स्वीकार करते हैं। बेशक, चूंकि सीएलआर पैरामीट्रिक प्रकारों के बारे में जानता है, इसलिए इसे जेनेरिक प्रकार की विशेषज्ञता पर ओवरलोडेड तरीकों को संभालने में कोई समस्या नहीं है।
दिन-प्रतिदिन के आधार पर, यही वह अंतर है जो मैं सीएलआर और जेवीएम के बीच सबसे अधिक नोटिस करता हूं।
अन्य महत्वपूर्ण अंतरों में शामिल हैं:
CLR में क्लोजर (C # डेलीगेट्स के रूप में लागू) है। JVM केवल जावा 8 के बाद से बंद होने का समर्थन करता है।
सीएलआर में कॉरआउट (सी # 'उपज' कीवर्ड के साथ लागू किया गया है)। जेवीएम नहीं करता है।
सीएलआर उपयोगकर्ता कोड को नए मूल्य प्रकार (संरचना) को परिभाषित करने की अनुमति देता है, जबकि जेवीएम मूल्य प्रकार (बाइट, लघु, इंट, लंबी, फ्लोट, डबल, चार, बूलियन) का एक निश्चित संग्रह प्रदान करता है और केवल उपयोगकर्ताओं को नए संदर्भ को परिभाषित करने की अनुमति देता है। प्रकार (कक्षाएं)।
सीएलआर पॉइंटर्स को घोषित करने और हेरफेर करने के लिए समर्थन प्रदान करता है। यह विशेष रूप से दिलचस्प है क्योंकि जेवीएम और सीएलआर दोनों अपनी मेमोरी-मैनेजमेंट रणनीति के रूप में सख्त जेनेरिक कॉम्पैक्टिंग कचरा कलेक्टर कार्यान्वयन को नियोजित करते हैं। सामान्य परिस्थितियों में, एक सख्त कॉम्पैक्टिंग जीसी में पॉइंटर्स के साथ वास्तव में कठिन समय होता है, क्योंकि जब आप एक मेमोरी लोकेशन से दूसरे में वैल्यू को स्थानांतरित करते हैं, तो सभी पॉइंटर्स (और पॉइंटर्स टू पॉइंटर्स) अमान्य हो जाते हैं। लेकिन सीएलआर एक "पिनिंग" तंत्र प्रदान करता है ताकि डेवलपर्स कोड के एक ब्लॉक की घोषणा कर सकें जिसके भीतर सीएलआर को कुछ बिंदुओं को स्थानांतरित करने की अनुमति नहीं है। यह बहुत सुविधाजनक है।
जेवीएम में कोड की सबसे बड़ी इकाई या तो एक 'पैकेज' है जिसे 'संरक्षित' कीवर्ड द्वारा प्रमाणिक रूप से दर्शाया गया है या यकीनन एक JAR (यानी जावा आर्काइव) के रूप में व्यक्त किया गया है, जो वर्गपथ में जार निर्दिष्ट करने में सक्षम है और इसे एक फ़ोल्डर की तरह माना जाता है कोड का। सीएलआर में, कक्षाओं को 'असेंबली' में एकत्रित किया जाता है, और एसएलआर असेंबलियों के बारे में तर्क और हेरफेर करने के लिए तर्क प्रदान करता है (जो "AppDomains" में लोड होता है, मेमोरी आवंटन और कोड निष्पादन के लिए उप-एप्लिकेशन-स्तर सैंडबॉक्स प्रदान करता है)।
सीएलआर बाईटेकोड प्रारूप (एमएसआईएल निर्देशों और मेटाडाटा से बना) में जेवीएम की तुलना में कम निर्देश प्रकार हैं। जेवीएम में, प्रत्येक अद्वितीय ऑपरेशन (दो अंतर मान जोड़ें, दो फ्लोट मान जोड़ें, आदि) का अपना अनूठा निर्देश है। सीएलआर में, एमएसआईएल के सभी निर्देश बहुरूपिए (दो मूल्य जोड़ें) हैं और जेआईटी कंपाइलर ऑपरेंड के प्रकारों को निर्धारित करने और उचित मशीन कोड बनाने के लिए जिम्मेदार है। मुझे नहीं पता कि कौन सी तरजीही रणनीति है, हालांकि। दोनों का ट्रेड-ऑफ है। हॉटस्पॉट जेआईटी संकलक, जेवीएम के लिए, एक सरल कोड-पीढ़ी तंत्र का उपयोग कर सकता है (इसे ऑपरेंड प्रकारों को निर्धारित करने की आवश्यकता नहीं है, क्योंकि वे पहले से ही निर्देश में एन्कोडेड हैं), लेकिन इसका मतलब है कि इसे और अधिक जटिल बायोटेक प्रारूप की आवश्यकता है, अधिक अनुदेश प्रकार के साथ।
मैं अब लगभग दस वर्षों से जावा (और जेवीएम को निहार रहा हूं) का उपयोग कर रहा हूं।
लेकिन, मेरी राय में, CLR अब लगभग हर तरह से बेहतर कार्यान्वयन है।