因为CLR是一个托管环境,所以运行时中有几个组件需要在执行任何代码之前初始化。本文将介绍EE(执行引擎)启动程序,并详细检查初始化过程。68只是一个粗略的指南,它取决于您使用的运行时版本、启用了哪些功能以及其他一些东西。

样例代码

假设你有一个最简单的C#程序,在CLR将“Hello World”输出到控制台之前会发生什么?

using System;

namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}

进入EE(执行引擎)的代码路径

当.NET可执行文件运行时,通过以下代码路径进入EE:

  1. _CorExeMain() (the external entry point)

    • call to _CorExeMainInternal()
  2. _CorExeMainInternal()
    • call to EnsureEEStarted()
  3. EnsureEEStarted()
    • call to EEStartup()
  4. EEStartup()
    • call to EEStartupHelper()
  5. EEStartupHelper()

因此,我们在EEStartupHelper()中结束,它在高层执行以下操作(来自ceemain.cpp中的注释)---EEStartup负责运行时的所有一次性初始化:

  • 创建默认和共享的appdomains。
  • 加载mscorlib.dll并加载基本类型(System.Object…)

EE(执行引擎)启动程序的主要阶段

下面的列表包含了从EEStartupHelper()调用的所有单独函数(~500 L.O.C)。为了使它们更容易理解,我们将它们分为不同的阶段:

  • 第1阶段-在运行其他任何东西之前,设置需要到位的基础设施
  • 第2阶段-初始化核心低层组件
  • 第3阶段-启动低级组件,即错误处理、Profiling  API、调试
  • 阶段4-启动主要组件,即垃圾收集器(GC)、AppDomains、安全性
  • 第5阶段-最终设置,然后通知其他组件EE已启动
注意:下面列表中的某些项仅在生成时定义了特定功能时才包含,这些项由ifdef语句中的包含来指示。还要注意的是,这些链接指向要调用的函数的代码,而不是EEStartupHelper()中的代码行。

第1阶段-在运行其他任何东西之前,设置需要到位的基础设施

  1. Wire-up console handling - SetConsoleCtrlHandler(..) (ifndef FEATURE_PAL)
  2. Initialise the internal SString class (everything uses strings!) - SString::Startup()
  3. Make sure the configuration is set-up, so settings that control run-time options can be accessed - EEConfig::Set-up() and InitializeHostConfigFile() (#if !defined(CROSSGEN_COMPILE))
  4. Initialize Numa and CPU group information - NumaNodeInfo::InitNumaNodeInfo() and CPUGroupInfo::EnsureInitialized() (#ifndef CROSSGEN_COMPILE)
  5. Initialize global configuration settings based on startup flags - InitializeStartupFlags()
  6. Set-up the Thread Manager that gives the runtime access to the OS threading functionality (StartThread(), Join(), SetThreadPriority() etc) - InitThreadManager()
  7. Initialize Event Tracing (ETW) and fire off the CLR startup events - InitializeEventTracing() and ETWFireEvent(EEStartupStart_V1) (#ifdef FEATURE_EVENT_TRACE)
  8. Set-up the GS Cookie (Buffer Security Check) to help prevent buffer overruns - InitGSCookie()
  9. Create the data-structures needed to hold the ‘frames’ used for stack-traces - Frame::Init()
  10. Ensure initialization of Apphacks environment variables - GetGlobalCompatibilityFlags() (#ifndef FEATURE_CORECLR)
  11. Create the diagnostic and performance logs used by the runtime - InitializeLogging() (#ifdef LOGGING) and PerfLog::PerfLogInitialize() (#ifdef ENABLE_PERF_LOG)

第2阶段-初始化核心低层组件

  1. Write to the log ===================EEStartup Starting===================
  2. Ensure that the Runtime Library functions (that interact with ntdll.dll) are enabled - EnsureRtlFunctions() (#ifndef FEATURE_PAL)
  3. Set-up the global store for events (mutexes, semaphores) used for synchronisation within the runtime - InitEventStore()
  4. Create the Assembly Binding logging mechanism a.k.a Fusion - InitializeFusion() (#ifdef FEATURE_FUSION)
  5. Then initialize the actual Assembly Binder infrastructure - CCoreCLRBinderHelper::Init() which in turn calls AssemblyBinder::Startup() (#ifdef FEATURE_FUSION is NOT defined)
  6. Set-up the heuristics used to control Monitors, Crsts, and SimpleRWLocks - InitializeSpinConstants()
  7. Initialize the InterProcess Communication with COM (IPC) - InitializeIPCManager() (#ifdef FEATURE_IPCMAN)
  8. Set-up and enable Performance Counters - PerfCounters::Init() (#ifdef ENABLE_PERF_COUNTERS)
  9. Set-up the CLR interpreter - Interpreter::Initialize() (#ifdef FEATURE_INTERPRETER), turns out that the CLR has a mode where your code is interpreted instead of compiled!
  10. Initialise the stubs that are used by the CLR for calling methods and triggering the JIT - StubManager::InitializeStubManagers(), also Stub::Init() and StubLinkerCPU::Init()
  11. Set up the core handle map, used to load assemblies into memory - PEImage::Startup()
  12. Startup the access checks options, used for granting/denying security demands on method calls - AccessCheckOptions::Startup()
  13. Startup the mscorlib binder (used for loading “known” types from mscorlib.dll) - MscorlibBinder::Startup()
  14. Initialize remoting, which allows out-of-process communication - CRemotingServices::Initialize() (#ifdef FEATURE_REMOTING)
  15. Set-up the data structures used by the GC for weak, strong and no-pin references - Ref_Initialize()
  16. Set-up the contexts used to proxy method calls across App Domains - Context::Initialize()
  17. Wire-up events that allow the EE to synchronise shut-down - g_pEEShutDownEvent->CreateManualEvent(FALSE)
  18. Initialise the process-wide data structures used for reader-writer lock implementation - CRWLock::ProcessInit() (#ifdef FEATURE_RWLOCK)
  19. Initialize the debugger manager - CCLRDebugManager::ProcessInit() (#ifdef FEATURE_INCLUDE_ALL_INTERFACES)
  20. Initialize the CLR Security Attribute Manager - CCLRSecurityAttributeManager::ProcessInit() (#ifdef FEATURE_IPCMAN)
  21. Set-up the manager for Virtual call stubs - VirtualCallStubManager::InitStatic()
  22. Initialise the lock that that GC uses when controlling memory pressure - GCInterface::m_MemoryPressureLock.Init(CrstGCMemoryPressure)
  23. Initialize Assembly Usage Logger - InitAssemblyUsageLogManager() (#ifndef FEATURE_CORECLR)

第3阶段-启动低级组件,即错误处理、Profiling API、调试

  1. Set-up the App Domains used by the CLR - SystemDomain::Attach() (also creates the DefaultDomain and the SharedDomain by calling SystemDomain::CreateDefaultDomain() and SharedDomain::Attach())
  2. Start up the ECall interface, a private native calling interface used within the CLR - ECall::Init()
  3. Set-up the caches for the stubs used by delegates - COMDelegate::Init()
  4. Set-up all the global/static variables used by the EE itself - ExecutionManager::Init()
  5. Initialise Watson, for windows error reporting - InitializeWatson(fFlags) (#ifndef FEATURE_PAL)
  6. Initialize the debugging services, this must be done before any EE thread objects are created, and before any classes or modules are loaded - InitializeDebugger() (#ifdef DEBUGGING_SUPPORTED)
  7. Activate the Managed Debugging Assistants that the CLR provides - ManagedDebuggingAssistants::EEStartupActivation() (ifdef MDA_SUPPORTED)
  8. Initialise the Profiling API - ProfilingAPIUtility::InitializeProfiling() (#ifdef PROFILING_SUPPORTED)
  9. Initialise the exception handling mechanism - InitializeExceptionHandling()
  10. Install the CLR global exception filter - InstallUnhandledExceptionFilter()
  11. Ensure that the initial runtime thread is created - SetupThread() in turn calls SetupThread(..)
  12. Initialise the PreStub manager (PreStub’s trigger the JIT) - InitPreStubManager() and the corresponding helpers StubHelpers::Init()
  13. Initialise the COM Interop layer - InitializeComInterop() (#ifdef FEATURE_COMINTEROP)
  14. Initialise NDirect method calls (lazy binding of unmanaged P/Invoke targets) - NDirect::Init()
  15. Set-up the JIT Helper functions, so they are in place before the execution manager runs - InitJITHelpers1() and InitJITHelpers2()
  16. Initialise and set-up the SyncBlock cache - SyncBlockCache::Attach() and SyncBlockCache::Start()
  17. Create the cache used when walking/unwinding the stack - StackwalkCache::Init()

阶段4-启动主要组件,即垃圾收集器(GC)、AppDomains、安全性

  1. Start up security system, that handles Code Access Security (CAS) - Security::Start() which in turn calls SecurityPolicy::Start()
  2. Wire-up an event to allow synchronisation of AppDomain unloads - AppDomain::CreateADUnloadStartEvent()
  3. Initialise the ‘Stack Probes’ used to setup stack guards InitStackProbes() (#ifdef FEATURE_STACK_PROBE)
  4. Initialise the GC and create the heaps that it uses - InitializeGarbageCollector()
  5. Initialise the tables used to hold the locations of pinned objects - InitializePinHandleTable()
  6. Inform the debugger about the DefaultDomain, so it can interact with it - SystemDomain::System()->PublishAppDomainAndInformDebugger(..) (#ifdef DEBUGGING_SUPPORTED)
  7. Initialise the existing OOB Assembly List (no idea?) - ExistingOobAssemblyList::Init() (#ifndef FEATURE_CORECLR)
  8. Actually initialise the System Domain (which contains mscorlib), so that it can start executing - SystemDomain::System()->Init()

第5阶段最终设置,然后通知其他组件EE已经启动了第4阶段-启动主要组件,即垃圾收集器(GC)、AppDomains、Security

  1. Tell the profiler we’ve stated up - SystemDomain::NotifyProfilerStartup() (#ifdef PROFILING_SUPPORTED)
  2. Pre-create a thread to handle AppDomain unloads - AppDomain::CreateADUnloadWorker() (#ifndef CROSSGEN_COMPILE)
  3. Set a flag to confirm that ‘initialisation’ of the EE succeeded - g_fEEInit = false
  4. Load the System Assemblies (‘mscorlib’) into the Default Domain - SystemDomain::System()->DefaultDomain()->LoadSystemAssemblies()
  5. Set-up all the shared static variables (and String.Empty) in the Default Domain - SystemDomain::System()->DefaultDomain()->SetupSharedStatics(), they are all contained in the internal class SharedStatics.cs
  6. Set-up the stack sampler feature, that identifies ‘hot’ methods in your code - StackSampler::Init() (#ifdef FEATURE_STACK_SAMPLING)
  7. Perform any once-only SafeHandle initialization - SafeHandle::Init() (#ifndef CROSSGEN_COMPILE)
  8. Set flags to indicate that the CLR has successfully started - g_fEEStarted = TRUE, g_EEStartupStatus = S_OK and hr = S_OK
  9. Write to the log ===================EEStartup Completed===================
 一旦这些都完成了,CLR现在就可以执行您的代码了!

执行用户代码

您的代码将通过以下代码流执行(在第一次被“JITted”之后):

  1. CorHost2::ExecuteAssembly()

    • calling ExecuteMainMethod()
  2. Assembly::ExecuteMainMethod()
    • calling RunMain()
  3. RunMain() (in assembly.cpp)
    • eventually calling into you main() method
    • full explanation of the ‘call’ process

转自:https://mattwarren.org/2017/02/07/The-68-things-the-CLR-does-before-executing-a-single-line-of-your-code/

在执行一行代码之前CLR做的68件事的更多相关文章

  1. 在执行一行代码之前CLR做的68件事[The 68 things the CLR does before executing a single line of your code]

    待翻译,原文地址:http://mattwarren.org/2017/02/07/The-68-things-the-CLR-does-before-executing-a-single-line- ...

  2. 安装 Kali Linux 后需要做的 20 件事

    安装 Kali Linux 后需要做的 20 件事 本文含有我觉得有用的每一件事情.本文分为三大部分: 专门针对Kali用户 Kali Linux是来自Debian的一个特殊版本,Kali Linux ...

  3. 安装 CentOS 7 后必做的七件事

    原文 安装 CentOS 7 后必做的七件事 CentOS 是最多人用来运行服务器的 Linux 版本,最新版本是 CentOS 7.当你兴趣勃勃地在一台主机或 VPS 上安装 CentOS 7 后, ...

  4. 刚安装Fedora 23工作站后,你必须要做的24件事

    [51CTO.com快译]Fedora 23工作站版本已发布,此后我们就一直在密切关注它.我们已经为新来读者介绍了一篇安装指南:<Fedora 23工作站版本安装指南> 还有一篇介绍如何从 ...

  5. 新手学习SEO要做的七件事是什么?

    学习SEO可能不那么先进的编程,学习SEO不可能掌握网页设计,学习SEO不需要学习SEO DIV + CSS;不是一个困难的任务,但是在学习过程中,如果你想掌握SEO,那么我们要做的几件事. 1.学习 ...

  6. 在 PHP 7 中不要做的 10 件事

    在 PHP 7 中不要做的 10 件事 1. 不要使用 mysql_ 函数 这一天终于来了,从此你不仅仅“不应该”使用mysql_函数.PHP 7 已经把它们从核心中全部移除了,也就是说你需要迁移到好 ...

  7. Ubuntu装完后要做的几件事

    Ubuntu装完后要做的几件事 改hosts 无论哪里,改hosts都是第一件事,没hosts咋google.没google咋活.在终端输入命令 sudo gedit /etc/hosts在# The ...

  8. 安装完Ubuntu 14.04要做的九件事

    www.linuxidc.com/Linux/2014-04/100411.htm 1.看看有哪些新特性 安装完之后的第一件事肯定是看看Ubuntu 14.04有哪些新的特性. Ubuntu 14.0 ...

  9. 亲身体验:digitalocean vps能做的10件事

    我写过一篇亲身体验:digitalocean和linode评测哪个好,帮助不少网友选购价格便宜性能优异的免备案vps,相信大家对两家产品有所了解.vps的性能和用途远远超过传统的虚拟主机,你拥有独立I ...

随机推荐

  1. 手把手教你 通过 NuGet.Server 包 搭建nuget服务器,并使用桌面工具上传 nuget 包,免命令行

    新建web项目 工具:VS2013 版本:.Net Framework 4.6,低版本也行,不过要找到对应版本的Nuget.Server 装了NuGet客户端(百度如何安装) WebForm或MVC都 ...

  2. django实战(三)--删除和批量删除

    上一节我们完成了带分页的模糊查询,本节我们继续删除操作. 同样的,先给出各个模块的代码(上一节的就不在贴出了):urls.py path('curd/delete/',views.curd_delet ...

  3. linux php composer安装和使用教程

    linux php composer安装和使用教程建议在linux下 下载后 然后再下载到本地               win上最好别用composer下载速度超级慢 或者根本下不动 项目依赖包 ...

  4. Navicat Premium 12 安装与激活

    一.Navicat Premium 12下载 官方下载地址:https://www.navicat.com.cn/download/navicat-premium 百度云盘:https://pan.b ...

  5. HTML -------- 标签、元素、属性,

    HTMl 中的标签.元素.属性, one.标签 :HTML是由一套标记标签 (markup tag)组成,通常就叫标签 标签由开始标签和结束标签组成 <p> 这是一个开始标签 </p ...

  6. scala的应用--UDF:用户自定义函数

    在window10下安装了hadoop,用ida创建maven项目. <properties> <spark.version>2.2.0</spark.version&g ...

  7. 【IntelliJ IDEA】idea部署服务到Tomcat的工作原理

    参考地址: https://blog.csdn.net/qq_41116058/article/details/81435084 为什么idea部署服务到tomcat时候,一定要修改Applicati ...

  8. 一段不错的代码JS的顶部轮播广告

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. file 从InputStream读取byte[]示例

    file 从InputStream读取byte[]示例 分类专栏: java基础   public static byte[] getStreamBytes(InputStream is) throw ...

  10. 关于VS C++中项目属性的一些名称的含义

    这个属性页(Alt + F7)界面下的$开头的内容的含义 $(Platform), X64或X86类似的. $(SolutionDir),.sln的位置 $(Configuration), Debug ...