问题描述
我的假设总是在CLR加载的所有它需要在应用程序域的启动时的DLL。不过,我已经写了,这让我怀疑这个假设的例子。我开始了我的应用程序和检查,看看有多少模块被加载。
My assumption was always that the CLR loaded all of the DLLs it needed on startup of the app domain. However, I've written an example that makes me question this assumption. I start up my application and check to see how many modules are loaded.
Process[] ObjModulesList;
ProcessModuleCollection ObjModulesOrig;
//Get all modules inside the process
ObjModulesList = Process.GetProcessesByName("MyProcessName");
// Populate the module collection.
ObjModulesOrig = ObjModulesList[0].Modules;
Console.WriteLine(ObjModulesOrig.Count.ToString());
然后我repeate完全相同的code和我的计算是不同的。额外的DLL是C:\\ WINNT \\ SYSTEM32 \\ VERSION.DLL
I then repeate the exact same code and my count is different. The additional DLL is C:\WINNT\system32\version.dll.
我,为什么数会有所不同真糊涂。
I'm really confused as to why the counts would be different.
可能有人请详细说明一下CLR在做什么,它是如何加载这些东西,通过什么逻辑,它这样做?
Could someone please elaborate on what the CLR is doing and how it's loading these thing, and by what logic it's doing so?
推荐答案
下面从Don Box的复制优秀的的基本的.Net 的。 (可这里)结果
(和,恕我直言,一个必须有任何专业.NET开发人员)
The following copied from Don Box's excellent Essential .Net. (available here)
(and, imho, a must have for any professional .Net developer)
CLR的装载机
的CLR装载机负责加载和初始化组件,模块,资源,和类型。 CLR的加载器加载和初始化不大,因为它可以逃脱。不同的是Win32加载时,CLR装载机不能解决与自动加载从属模块(或组件)。
相反,下属件装上,只有当他们真正需要(如使用Visual C ++ 6.0的延迟加载功能)的需求。这不仅加快了程序初始化时间,而且减少了一个正在运行的程序所消耗的资源量。
在CLR,负载通常是由基于类型即时(JIT)编译器触发。当JIT编译器试图将方法体由CIL转换成机器code,它需要访问声明作为类型的字段类型定义,类型以及类型定义。此外,JIT编译器还需要访问任何局部变量或方法是JIT编译参数使用的类型定义。装载型意味着加载两个组件和包含该类型定义的模块。
装载类型(和组件和模块)上的需求此策略意味着未使用的程序的部分从未带入内存。这也意味着,运行的应用程序,经常会看到加载随时间的新组件和模块,在执行过程中,需要包含在这些文件中的类型。如果这不是你想要的行为,你有两个选择。一种是简单地声明要与装载机明确相互作用的类型的隐藏静态字段。
The CLR Loader is responsible for loading and initializing assemblies, modules, resources, and types. The CLR loader loads and initializes as little as it can get away with. Unlike the Win32 loader, the CLR loader does not resolve and automatically load the subordinate modules (or assemblies).Rather, the subordinate pieces are loaded on demand only if they are actually needed (as with Visual C++ 6.0's delay-load feature). This not only speeds up program initialization time but also reduces the amount of resources consumed by a running program.In the CLR, loading typically is triggered by the just in time (JIT) compiler based on types. When the JIT compiler tries to convert a method body from CIL to machine code, it needs access to the type definition of the declaring type as well as the type definitions for the type's fields. Moreover, the JIT compiler also needs access to the type definitions used by any local variables or parameters of the method being JIT-compiled. Loading a type implies loading both the assembly and the module that contain the type definition.This policy of loading types (and assemblies and modules) on demand means that parts of a program that are not used are never brought into memory. It also means that a running application will often see new assemblies and modules loaded over time as the types contained in those files are needed during execution. If this is not the behavior you want, you have two options. One is to simply declare hidden static fields of the types you want to interact with the loader explicitly.
装载机通常做的工作隐含代为通知。开发人员可以通过组装装载机装载机显式的交互。组装装载机暴露通过对 System.Reflection.Assembly
类 LoadFrom
静态方法的开发。该方法接受一个codeBase的字符串,它可以是一个文件系统路径或统一资源定位符(URL),该标识包含集清单的模块。如果无法找到指定的文件,加载器将抛出一个 System.FileNotFoundException
例外。如果指定的文件可以发现,但不包含程序集清单一个CLR模块,加载器将抛出一个 System.BadImageFormatException
例外。最后,如果codeBase的是使用其他的方案比文件的URL:
,调用者必须具有WebPermission的访问权限,否则一个系统.SecurityException
异常。此外,在网址中比其他协议组件文件:
先下载到下载缓存加载之前
The loader typically does its work implicitly on your behalf. Developers can interact with the loader explicitly via the assembly loader. The assembly loader is exposed to developers via the LoadFrom
static method on the System.Reflection.Assembly
class. This method accepts a CODEBASE string, which can be either a file system path or a uniform resource locator (URL) that identifies the module containing the assembly manifest. If the specified file cannot be found, the loader will throw a System.FileNotFoundException
exception. If the specified file can be found but is not a CLR module containing an assembly manifest, the loader will throw a System.BadImageFormatException
exception. Finally, if the CODEBASE is a URL that uses a scheme other than file:
, the caller must have WebPermission access rights or else a System.SecurityException
exception is thrown. Additionally, assemblies at URLs with protocols other than file:
are first downloaded to the download cache prior to being loaded.
清单2.2显示加载位于汇编文件的简单的C#程序:// C:/usr/bin/xyzzy.dll
,然后创建的一个实例命名包含的类型 AcmeCorp.LOB.Customer
。在这个例子中,由该呼叫者提供的所有是该组件的物理位置。
当一个程序使用以这种方式组装加载器,CLR忽略组件的四部分组成的名称,包括它的版本号。
Listing 2.2 shows a simple C# program that loads an assembly located at file://C:/usr/bin/xyzzy.dll
and then creates an instance of the contained type named AcmeCorp.LOB.Customer
. In this example, all that is provided by the caller is the physical location of the assembly.When a program uses the assembly loader in this fashion, the CLR ignores the four-part name of the assembly, including its version number.
例2. 2.装载程序集具有显式codeBase的
Example 2. 2. Loading an Assembly with an Explicit CODEBASE
using System;
using System.Reflection;
public class Utilities {
public static Object LoadCustomerType() {
Assembly a = Assembly.LoadFrom(
"file: //C:/usr/bin/xyzzy. dll") ;
return a.CreateInstance("AcmeCorp.LOB.Customer") ;
}
}
虽然位置加载程序集是有点有趣,大部分组件是按名称使用汇编解析器加载。该组件采用解析器的四个零件装配名称确定底层的文件使用汇编加载器加载到内存中。如图图2.9 ,这个名字到位置的解析过程考虑到多种因素,包括应用托管的目录,版本控制政策,以及其他配置细节(所有这些都是在本章后面讨论)。
Although loading assemblies by location is somewhat interesting, most assemblies are loaded by name using the assembly resolver. The assembly resolver uses the four-part assembly name to determine which underlying file to load into memory using the assembly loader. As shown in Figure 2.9, this name-to-location resolution process takes into account a variety of factors, including the directory the application is hosted in, versioning policies, and other configuration details (all of which are discussed later in this chapter).
装配解析器是通过加载
的 System.Reflection.Assembly
类的方法暴露给开发者。如清单2.3所示,该方法接受一个四部分组成的程序集的名称(或者作为一个字符串或作为参考的AssemblyName)和表面上似乎是类似于组装装载机暴露LoadFrom方法。相似深的原因是Load方法首先使用装配解析器找到使用一个相当复杂的一系列操作合适的文件只肌肤。第一这些操作是应用版本策略来准确地确定该期望的组件的版本应装载
The assembly resolver is exposed to developers via the Load
method of the System.Reflection.Assembly
class. As shown in Listing 2.3, this method accepts a four-part assembly name (either as a string or as an AssemblyName reference) and superficially appears to be similar to the LoadFrom method exposed by the assembly loader. The similarity is only skin deep because the Load method first uses the assembly resolver to find a suitable file using a fairly complex series of operations. The first of these operations is to apply a version policy to determine exactly which version of the desired assembly should be loaded.
例2.3。加载一个装配使用大会解析器
Example 2.3. Loading an Assembly Using the Assembly Resolver
using System;
using System.Reflection;
public class Utilities {
public static Object LoadCustomerType() {
Assembly a = Assembly.Load(
"xyzzy, Version=1. 2. 3.4, " +
"Culture=neutral, PublicKeyToken=9a33f27632997fcc") ;
return a.CreateInstance("AcmeCorp.LOB.Customer") ;
}
}
这篇关于如何是由CLR加载的DLL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!