I have been developing apps using .net for quite sometime now. But, I am still not sure how does the CLR know that a .net app has started. Is there like one instance of CLR per app? I don't think this can be the case as there is just one GC which manages all the memory for all .net apps. Does the CLR kind of run in background? I am quite confused.
问题:
回答1:
Hmm, let me take a shot at this too.
Somebody builds a .NET application in C#, or .NET 'Intermediate Language', or another managed language.
The compiler for that language csc.exe (C#), or ilasm.exe (bytecode assembler), or whichever, produces a PE executable. The PE executable has a specific structure that the compiler or assembler populates. That includes:
- an entry point, and
- a list of dynamic libraries that it uses (the IMPORT table). One of those libraries is mscoree.dll
- lots of metadata, including the targeted .NET runtime version
When the executable is clicked on, ran from the command line, or executed from a Win32 API, the Windows loader implementation (in NTDLL.dll) takes over
The loader code is responsible for getting the executable into memory, loading dynamic link libraries if needed, mapping linked libraries into a place the executable code can reach them, and updating the Import Address Table with the actual addresses of the mapped libraries.
Once all is ready, the loader jumps to the entry point (through what I assume is some shenanigans switching from kernel space to user space, or to protected mode, since the application runs in it's own protected 32 or 64 bit memory space). The entry point goes to mscoree.dll - the .NET Common Object Runtime Execution Engine, which was just mapped into the processes memory. I've seen this DLL referred to as the .NET startup shim, and it allows the multiple installs of .NET to exist on one machine. Mscoree.dll is the library you'll use if you are embedding a .NET language in your own regular application.
Mscoree.dll looks at the metadata loaded from the PE executable, specifically the CLR header, and the targeted .NET runtime version. From that it can CorBindToRuntimeEx2 to the right CLR version.
The CorBindToRuntimeEx loads the correct .NET runtime implementation (and returns a pointer to a COM interface allowing you to invoke that .NET runtime. This code is loaded from the dlls in %WINDIR%\Microsoft.NET\Framework\v#####.
I'm not sure who at this point, but probably the mscoree shim uses the .NET ICLRRuntimeHost interface pointer to invoke methods to initialize the .NET runtime, garbage collector, IL interpreter, JIT and IHostControl interfaces (that allow the .NET interpreter to talk back to the hosting process), and ultimately tells the Interpreter to start executing your compiled application's IL code.
(I learnt a lot writing this - there is a ton of information behind the links, I certainly didn't get through all of it!)
http://msdn.microsoft.com/en-us/library/xh0859k0.aspx
http://my.safaribooksonline.com/book/programming/microsoft-dotnet/0735619883/a-tour-of-the-clr-hosting-api/ch02lev1sec3
http://msdn.microsoft.com/en-us/magazine/bb985994.aspx
回答2:
Windows executables are Portable Executables, a format which gives Windows the information it needs to load and run the program. When Windows encounters a .NET program it loads an instance of the CLR and hands execution of the program to the new CLR instance. Each running .NET program is hosted within it's own instance of the CLR.
The CLR process loads the IL program and compiles it to Native Code (JIT) then executes the code, taking care of memory management and garbage collection for that program.