在执行一行代码之前CLR做的68件事
因为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:
- _CorExeMain() (the external entry point)
- call to _CorExeMainInternal()
- _CorExeMainInternal()
- call to EnsureEEStarted()
- EnsureEEStarted()
- call to EEStartup()
- EEStartup()
- call to EEStartupHelper()
- 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已启动
第1阶段-在运行其他任何东西之前,设置需要到位的基础设施
- Wire-up console handling - SetConsoleCtrlHandler(..) (
ifndef FEATURE_PAL
) - Initialise the internal
SString
class (everything uses strings!) - SString::Startup() - 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)
) - Initialize Numa and CPU group information - NumaNodeInfo::InitNumaNodeInfo() and CPUGroupInfo::EnsureInitialized() (
#ifndef CROSSGEN_COMPILE
) - Initialize global configuration settings based on startup flags - InitializeStartupFlags()
- Set-up the Thread Manager that gives the runtime access to the OS threading functionality (
StartThread()
,Join()
,SetThreadPriority()
etc) - InitThreadManager() - Initialize Event Tracing (ETW) and fire off the CLR startup events - InitializeEventTracing() and ETWFireEvent(EEStartupStart_V1) (
#ifdef FEATURE_EVENT_TRACE
) - Set-up the GS Cookie (Buffer Security Check) to help prevent buffer overruns - InitGSCookie()
- Create the data-structures needed to hold the ‘frames’ used for stack-traces - Frame::Init()
- Ensure initialization of Apphacks environment variables - GetGlobalCompatibilityFlags() (
#ifndef FEATURE_CORECLR
) - Create the diagnostic and performance logs used by the runtime - InitializeLogging() (
#ifdef LOGGING
) and PerfLog::PerfLogInitialize() (#ifdef ENABLE_PERF_LOG
)
第2阶段-初始化核心低层组件
- Write to the log
===================EEStartup Starting===================
- Ensure that the Runtime Library functions (that interact with ntdll.dll) are enabled - EnsureRtlFunctions() (
#ifndef FEATURE_PAL
) - Set-up the global store for events (mutexes, semaphores) used for synchronisation within the runtime - InitEventStore()
- Create the Assembly Binding logging mechanism a.k.a Fusion - InitializeFusion() (
#ifdef FEATURE_FUSION
) - Then initialize the actual Assembly Binder infrastructure - CCoreCLRBinderHelper::Init() which in turn calls AssemblyBinder::Startup() (
#ifdef FEATURE_FUSION
is NOT defined) - Set-up the heuristics used to control Monitors, Crsts, and SimpleRWLocks - InitializeSpinConstants()
- Initialize the InterProcess Communication with COM (IPC) - InitializeIPCManager() (
#ifdef FEATURE_IPCMAN
) - Set-up and enable Performance Counters - PerfCounters::Init() (
#ifdef ENABLE_PERF_COUNTERS
) - 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! - Initialise the stubs that are used by the CLR for calling methods and triggering the JIT - StubManager::InitializeStubManagers(), also Stub::Init() and StubLinkerCPU::Init()
- Set up the core handle map, used to load assemblies into memory - PEImage::Startup()
- Startup the access checks options, used for granting/denying security demands on method calls - AccessCheckOptions::Startup()
- Startup the mscorlib binder (used for loading “known” types from mscorlib.dll) - MscorlibBinder::Startup()
- Initialize remoting, which allows out-of-process communication - CRemotingServices::Initialize() (
#ifdef FEATURE_REMOTING
) - Set-up the data structures used by the GC for weak, strong and no-pin references - Ref_Initialize()
- Set-up the contexts used to proxy method calls across App Domains - Context::Initialize()
- Wire-up events that allow the EE to synchronise shut-down -
g_pEEShutDownEvent->CreateManualEvent(FALSE)
- Initialise the process-wide data structures used for reader-writer lock implementation - CRWLock::ProcessInit() (
#ifdef FEATURE_RWLOCK
) - Initialize the debugger manager - CCLRDebugManager::ProcessInit() (
#ifdef FEATURE_INCLUDE_ALL_INTERFACES
) - Initialize the CLR Security Attribute Manager - CCLRSecurityAttributeManager::ProcessInit() (
#ifdef FEATURE_IPCMAN
) - Set-up the manager for Virtual call stubs - VirtualCallStubManager::InitStatic()
- Initialise the lock that that GC uses when controlling memory pressure - GCInterface::m_MemoryPressureLock.Init(CrstGCMemoryPressure)
- Initialize Assembly Usage Logger - InitAssemblyUsageLogManager() (
#ifndef FEATURE_CORECLR
)
第3阶段-启动低级组件,即错误处理、Profiling API、调试
- 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())
- Start up the ECall interface, a private native calling interface used within the CLR - ECall::Init()
- Set-up the caches for the stubs used by
delegates
- COMDelegate::Init() - Set-up all the global/static variables used by the EE itself - ExecutionManager::Init()
- Initialise Watson, for windows error reporting - InitializeWatson(fFlags) (
#ifndef FEATURE_PAL
) - 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
) - Activate the Managed Debugging Assistants that the CLR provides - ManagedDebuggingAssistants::EEStartupActivation() (
ifdef MDA_SUPPORTED
) - Initialise the Profiling API - ProfilingAPIUtility::InitializeProfiling() (
#ifdef PROFILING_SUPPORTED
) - Initialise the exception handling mechanism - InitializeExceptionHandling()
- Install the CLR global exception filter - InstallUnhandledExceptionFilter()
- Ensure that the initial runtime thread is created - SetupThread() in turn calls SetupThread(..)
- Initialise the PreStub manager (PreStub’s trigger the JIT) - InitPreStubManager() and the corresponding helpers StubHelpers::Init()
- Initialise the COM Interop layer - InitializeComInterop() (
#ifdef FEATURE_COMINTEROP
) - Initialise NDirect method calls (lazy binding of unmanaged P/Invoke targets) - NDirect::Init()
- Set-up the JIT Helper functions, so they are in place before the execution manager runs - InitJITHelpers1() and InitJITHelpers2()
- Initialise and set-up the SyncBlock cache - SyncBlockCache::Attach() and SyncBlockCache::Start()
- Create the cache used when walking/unwinding the stack - StackwalkCache::Init()
阶段4-启动主要组件,即垃圾收集器(GC)、AppDomains、安全性
- Start up security system, that handles Code Access Security (CAS) - Security::Start() which in turn calls SecurityPolicy::Start()
- Wire-up an event to allow synchronisation of AppDomain unloads - AppDomain::CreateADUnloadStartEvent()
- Initialise the ‘Stack Probes’ used to setup stack guards InitStackProbes() (
#ifdef FEATURE_STACK_PROBE
) - Initialise the GC and create the heaps that it uses - InitializeGarbageCollector()
- Initialise the tables used to hold the locations of pinned objects - InitializePinHandleTable()
- Inform the debugger about the DefaultDomain, so it can interact with it - SystemDomain::System()->PublishAppDomainAndInformDebugger(..) (
#ifdef DEBUGGING_SUPPORTED
) - Initialise the existing OOB Assembly List (no idea?) - ExistingOobAssemblyList::Init() (
#ifndef FEATURE_CORECLR
) - Actually initialise the System Domain (which contains mscorlib), so that it can start executing - SystemDomain::System()->Init()
第5阶段最终设置,然后通知其他组件EE已经启动了第4阶段-启动主要组件,即垃圾收集器(GC)、AppDomains、Security
- Tell the profiler we’ve stated up - SystemDomain::NotifyProfilerStartup() (
#ifdef PROFILING_SUPPORTED
) - Pre-create a thread to handle AppDomain unloads - AppDomain::CreateADUnloadWorker() (
#ifndef CROSSGEN_COMPILE
) - Set a flag to confirm that ‘initialisation’ of the EE succeeded -
g_fEEInit = false
- Load the System Assemblies (‘mscorlib’) into the Default Domain - SystemDomain::System()->DefaultDomain()->LoadSystemAssemblies()
- 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 - Set-up the stack sampler feature, that identifies ‘hot’ methods in your code - StackSampler::Init() (
#ifdef FEATURE_STACK_SAMPLING
) - Perform any once-only SafeHandle initialization - SafeHandle::Init() (
#ifndef CROSSGEN_COMPILE
) - Set flags to indicate that the CLR has successfully started -
g_fEEStarted = TRUE
,g_EEStartupStatus = S_OK
andhr = S_OK
- Write to the log
===================EEStartup Completed===================
执行用户代码
您的代码将通过以下代码流执行(在第一次被“JITted”之后):
- CorHost2::ExecuteAssembly()
- calling ExecuteMainMethod()
- Assembly::ExecuteMainMethod()
- calling RunMain()
- 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件事的更多相关文章
- 在执行一行代码之前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- ...
- 安装 Kali Linux 后需要做的 20 件事
安装 Kali Linux 后需要做的 20 件事 本文含有我觉得有用的每一件事情.本文分为三大部分: 专门针对Kali用户 Kali Linux是来自Debian的一个特殊版本,Kali Linux ...
- 安装 CentOS 7 后必做的七件事
原文 安装 CentOS 7 后必做的七件事 CentOS 是最多人用来运行服务器的 Linux 版本,最新版本是 CentOS 7.当你兴趣勃勃地在一台主机或 VPS 上安装 CentOS 7 后, ...
- 刚安装Fedora 23工作站后,你必须要做的24件事
[51CTO.com快译]Fedora 23工作站版本已发布,此后我们就一直在密切关注它.我们已经为新来读者介绍了一篇安装指南:<Fedora 23工作站版本安装指南> 还有一篇介绍如何从 ...
- 新手学习SEO要做的七件事是什么?
学习SEO可能不那么先进的编程,学习SEO不可能掌握网页设计,学习SEO不需要学习SEO DIV + CSS;不是一个困难的任务,但是在学习过程中,如果你想掌握SEO,那么我们要做的几件事. 1.学习 ...
- 在 PHP 7 中不要做的 10 件事
在 PHP 7 中不要做的 10 件事 1. 不要使用 mysql_ 函数 这一天终于来了,从此你不仅仅“不应该”使用mysql_函数.PHP 7 已经把它们从核心中全部移除了,也就是说你需要迁移到好 ...
- Ubuntu装完后要做的几件事
Ubuntu装完后要做的几件事 改hosts 无论哪里,改hosts都是第一件事,没hosts咋google.没google咋活.在终端输入命令 sudo gedit /etc/hosts在# The ...
- 安装完Ubuntu 14.04要做的九件事
www.linuxidc.com/Linux/2014-04/100411.htm 1.看看有哪些新特性 安装完之后的第一件事肯定是看看Ubuntu 14.04有哪些新的特性. Ubuntu 14.0 ...
- 亲身体验:digitalocean vps能做的10件事
我写过一篇亲身体验:digitalocean和linode评测哪个好,帮助不少网友选购价格便宜性能优异的免备案vps,相信大家对两家产品有所了解.vps的性能和用途远远超过传统的虚拟主机,你拥有独立I ...
随机推荐
- 版本分支管理标准 - Trunk Based Development 主干开发模型
之前分享过<版本分支管理标准 - Git Flow>,不过在实际使用过程中, 因为其有一定的复杂度,使用起来较为繁琐,所以一些人员较少的团队并不会使用这个方案. 在这基础上,一些新的分支管 ...
- Dubbo简介与使用
1:Dubbo是什么 阿里生产的一种rpc 实现框架 Dubbo 是一个分布式服务框架,是阿里巴巴开源项目 ,被国内电商及互联网项目中使用. Dubbo 致力于提供高性能和透明化的RPC远程服务调用 ...
- Luogu P3879 【[TJOI2010]阅读理解】
前言: 这个题一直有个疑问,最多一千行,每行五千字$1000\times5000=5e6$ $5e6\times26\times4\div1024\div1024\approx496Mb>125 ...
- Android Studio Analyze APK 一直显示 Parsing Manifest探因及解决
一.背景 大家都知道,Android Studio开发工具自带了Analyze Apk,可以很方便的分析Apk文件.具体位于菜单build >> Analyze APK...路径下,点击后 ...
- 目标检测算法之Fast R-CNN和Faster R-CNN原理
一.Fast R-CNN原理 在SPPNet中,实际上特征提取和区域分类两个步骤还是分离的.只是使用ROI池化层提取了每个区域的特征,在对这些区域分类时,还是使用传统的SVM作为分类器.Fast R- ...
- JavaIO学习:缓冲流
缓冲流 1.缓冲流涉及到的类 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter 2.作用 提升流的读取.写入 ...
- Redis 分析部分功能所解决的问题
前言:说到缓存,大家都会想到redis,而redis中又有各种眼花缭乱的功能,今天就来看看这些功能能解决的问题. Redis官方简介 Redis是一个基于BSD开源的项目,是一个把结构化的数据放在内存 ...
- 2019-11-29-WPF-测试触摸设备发送触摸按下和抬起不成对
原文:2019-11-29-WPF-测试触摸设备发送触摸按下和抬起不成对 title author date CreateTime categories WPF 测试触摸设备发送触摸按下和抬起不成对 ...
- 小白开学Asp.Net Core 《八》
小白开学Asp.Net Core <八> — — .Net Core 数据保护组件 1.背景 我在搞(https://github.com/AjuPrince/Aju.Carefree)这 ...
- Form之action提交不刷新不跳转
<div class="file-box"> <form action="/File/fileUpLoad" id="form1&q ...