How CLR executes .NET Application?

How CLR Executes the Application: CLR में बहुत सारे Components होते हैं, जो कि .NET Assemblies के Execution व Management को Support करते हैं, लेकिन हम इन सभी की Detail में न जाकर केवल Major Components के बारे में ही बात करेंगे, जिन्हें निम्न चित्र द्वारा समझा जा सकता है:

How CLR executes the Application - C# in Hindi

जैसाकि इस चित्र में हम देख सकते हैं कि .NET PE File, CLR के Top पर Run होता है। यानी इसी .NET PE File को .NET Platform का CLR Layer अपने Virtual Execution Engine (VEE) में Execute करता है, जो कि CLR के Runtime के विभिन्न Major Components को Host करता है।

Class Loader

जब हम किसी Standard Windows Application को Run करते हैं, तो OS Loader उस Application को तभी Execute कर सकता है, जबकि Application पहले से Loaded हो। इसलिए OS Loader उस Application को Execute करने से पहले Load करता है।

.NET Framework द्वारा .EXE/.DLL Assembly के रूप में जो Class Files Generate होती हैं, उन्हें Execute करने के लिए Microsoft ने .NET Runtime में ही एक OS Loader Create किया है, जो जानता है कि .NET PE File Format को किस प्रकार से Load करके Handle करना है।

परिणामस्वरूप जैसे ही हम किसी  .NET Application को Run करते हैं, Current Operating System पर Installed .NET Framework के Platform का OS Loader उस .NET Application को Recognize करता है और उस Application का Control CLR को Pass कर देता है।

फिर CLR उस Application के Code में Entry Point को Search करता है, जो कि WinMain(), Main() या DllMain() में से कोई एक होता है और जैसे ही उसे Entry Point मिल जाता है, CLR उस Application का Execution Start कर देता है।

लेकिन इससे पहले इससे पहले कि Application का Execution Start हो, CLR के Class Loader Part को Current Application के उस Class को Find करना होता है, जिसमें Entry Point (Main(), WinMain(), DllMain()) को Specify किया गया है और उस Class को Search करके उसे Load करना होता है।

इसी तरह से जब Entry Point की Class में किसी अन्‍य Class का Object Crate किया जाता है, तब भी Class Loader Trigger होता है और उस Class को Load कर देता है, जिसका Object Create किया जा रहा है।

यानी पूरे Application Execution के दौरान जब भी कभी किसी Class को या किसी Type को Reference किया जाता है, Class Loader Activate होकर उस Class को Load कर देता है और क्योंकि किसी भी Application में बहुत सारी प्रकार की Classes व Types को Reference किया जाता है, इसलिए पूरे Application के Life Cycle के दौरान Class Loader कई बार Trigger होता है।

Class Loader का मुख्‍य काम यही है कि वह Current Code Line में किसी Reference की गई Class को Memory में Load करता है तथा Execute होने के लिए उसे Prepare करता है और Class Loader ये काम Successfully कर सके, इससे लिए Class Loader को पहले उस Target Class को Locate करना होता है।

Target Class को Locate करने के लिए Class Loader Current Application की Current Directory में Configuration File (.config), GACPE File के METADATAMANIFEST को Search करता है और इन में से जो भी उस Target Class File के विषय में Information Provide करता है, उसे Use करते हुये Class File को Memory में Load करके Execution के लिए Prepare कर देता है।

यहां एक बात विशेष रूप से समझने वाली है और वो ये है कि कोई Class किसी Particular Namespace में Hosted हो सकता है, कोई Namespace किसी Particular Assembly में Hosted हो सकता है और कोई Assembly किसी Particulare Specific Version से Associated हो सकता है।

इसलिए अलग-अलग Version, Assembly या Namespace में समान नाम की Classes Exist हो सकती है और Current Application किस Class को Reference कर रहा है, इसका पता लगाने के लिए Class Loader Current Application की Current Directory में Configuration File (.config), GACPE File के METADATA व MANIFEST को Search करता है।

जब एक बार Class Loader को Appropriate Target Class प्राप्त हो जाता है, तो Class Loader उस Class की Information को Cache Memory में Store कर देता है, ताकि यदि इसी Class को फिर से Load करने की जरूरत पडे, तो Class Loader उस Class को Cache Memory से ही प्राप्त कर ले।

साथ ही Class को Cache Memory में Store करके Class Loader इस बात का पता लगाता है कि Target Class के Instance Object को Create करके Load करने के लिए कितनी Memory की जरूरत होगी।

जब एक बार Target Class Load हो जाती है, तो Class Loader, Loaded Class के हर Method में एक Stub यानी ऐसा कोई Mark Inject करता है। इस Injected Stub को दो कामों को पूरा करने के लिए Use किया जाता है।

  • JIT Compilation की Status का पता इसी Stub से चलता है।
  • Managed व Unmanaged Codes के बीच Transition के लिए इसी Stub को Use किया जाता है।

इस Point तक पहुंचने तक यदि Class Loader द्वारा Currently Loaded Class स्वयं किसी अन्‍य External Class को Reference करता है, तो Class Loader उस External Referenced Class को भी Load करने की कोशिश करता है। जबकि यदि Referenced Type पहले से ही Loaded हो, तो उस स्थिति में Class Loader कुछ भी नहीं करता।

अन्त में ये Class Loader Appropriate METADATA को Use करते हुए Loaded Target Class के Static Variables को Initialize करता है और Loaded Class को Instantiate करते हुए उसका Object Create करता है।

Verifier

Scripting व Interpreted Languages में कोई निश्चित तरीका नहीं होता, जिससे Type या Class का पता लगाया जा सके और सामान्‍यत: Scripting Languages हमें बिना Variable को Manually Declare किए हुए Directly Define करते हुए Use करने की सुविधा Provide करते हैं। इसलिए जब हम .NET Framework को किसी Ruby जैसी किसी Scripting Language द्वारा Use करने की कोशिश करते हैं, तब इस प्रकार के Programs को Manage व Maintain करना काफी मुश्किल होता है।

जबकि Scripting व Interpreted Languages की तुलना में Compiled Languages में विभिन्न Variables को Use करने से पहले उन्हें Declare करना जरुरी होता है। इसलिए Compiler Based Programming Languages कम Error Prone व ज्यादा Perfect तरीके से Runtime में Execute होते हैं।

CLR के इस Section द्वारा Code Verification किया जाता है और Code Verification करने का पूरा Concept Type Safety पर निर्भर है। Type Safety एक ऐसी प्रक्रिया है, जिसमें इस बात को निश्चित किया जाता है कि जिस किसी भी Variable को Application में Use किया गया है, उसे निश्चित रूप से Declare भी किया गया है।

.NET का Type Safety Test Perform करने का काम Verifier करता है और Runtime में Type Safety को Verify करने के बाद यदि Code Execute होने के लिए Safe होता है, तो वह Code JIT Compiler पर जाता है अन्‍यथा CLR उस Code को Execute होने से रोक देता है।

जब Class Loader किसी Target Class को Memory में Load कर देता है और Class के Load होने के बाद जब IL Code Execute होने के लिए तैयार होता है, उससे Just पहले Verifier Trigger होता है जो कि Execute होने वाले Code को निम्न स्थितियों के आधार पर Verify करता है:

  • METADATA Well Formatted है या नहीं।
  • IL Code Type Safe हैं या नहीं।

यदि उपरोक्त दोनों ही बातें ठीक हों, यानी यदि Currently Loaded Assembly का METADATA Well Format में हो तथा Assembly का IL Code Type Safe हो यानी विभिन्न Type Signature बिल्कुल सही हों, तो Current Assembly का Code JIT Compilation पर भेजे जाने योग्; होने के लिए Verify हो जाता है।

चूंकि Verifiers, CLR के JIT Compilers Part का ही हिस्सा हैं, इसलिए ये केवल तभी Trigger होता है, जब Class के Method को Invoke किया जाता है न कि तब जब Class या Assembly Load होता है।

साथ ही यहां इस बात का भी ध्‍यान रखना चाहि, कि Verification एक Optional Step है। इसलिए Trusted Code हमेंशा Directly JIT Compilers पर Compilation के लिए Redirect हो जाते हैं।

JIT Compilers

.NET Platform में JIT Compilers बहुत ही महत्वपूर्ण Role Play करते हैं क्योंकि सभी .NET PE Files में ILMETADATA Code होता है, Executable Native Code नहीं। इसलिए JIT Compilers हमेंशा इन IL Code को Native Code में Convert करता है, ताकि Target Operating System उन Codes को Execute कर सके।

हर वह Method, जो कि CLR के Verifier Stage को Pass कर चुका होता है, उसे CLR का JIT Compiler Compile करके Managed Native Code में Convert कर देता है। Managed Native Code की जरूरत इसलिए होती है क्योंकि CLR का अगला Part, जिसे Executing Support Components के नाम से जाना जाता है, केवल Managed Code को ही Manage व Execute करता है।

JIT Compilers का एक Advantage ये है कि ये किसी Target Machine के लिए Optimized Code को Dynamically Compile कर देता है। यानी यदि हम Same .NET PE File को एक 1-CPU Machine से 2-CPU Machine पर ले जाऐं, तो उस 2-CPU Machine का JIT Compiler को उस दूसरे CPU के बारे में पता होता है और वह Native Code को दो हिस्सों में Divide करके दूसरे CPU को भी Application Execution के लिए उपयोग में ले लेता है।

JIT Compilers का दूसरा मुख्‍य फायदा ये है कि हम समान .NET PE File को किसी भी अन्‍य .NET Platform या CLR Installed Operating System (Windows, Linux, Unix, MacOS, etc…) पर समान प्रकार से Run कर सकते हैं।

Optimization Reasons की वजह से हर Method का JIT Compilation केवल एक बार ही होता है, जब किसी Method को First Time Invoke किया जाता है। क्योंकि जैसे ही किसी Method को Call किया जाता है, Class Loader उसमें एक Stub Inject कर देता है, जिससे जब हम दुबारा उसी Method को Call करते हैं, तो CLR को उस Method में Stub मिलता है, जिससे उसे पता चल जाता है कि उस Method को पहले भी Compile किया जा चुका है। परिणामस्वरूप CLR का JIT Compiler उस Method को दुबारा Native Machine Code में Convert नहीं करता। (How CLR Executes the Application)

Assembly in C#
Base Class Library in .NET

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW GET DEMO REVIEWS