在执行一行代码之前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 ...
随机推荐
- LeetCode 485:连续最大1的个数 Max Consecutive Ones(python java)
公众号:爱写bug 给定一个二进制数组, 计算其中最大连续1的个数. Given a binary array, find the maximum number of consecutive 1s i ...
- 详解golang net之netpoll
golang版本1.12.9:操作系统:readhat 7.4 golang的底层使用epoll来实现IO复用.netPoll通过pollDesc结构体将文件描述符与底层进行了绑定.netpoll实现 ...
- loonflow 工单系统
该项目是基于django的工作流引擎,工单.项目托管在 Github 一.安装基础环境 1.1 安装python 和 pip yum install -y epel-release yum insta ...
- 19条常用的MySQL优化方法(转)
本文我们来谈谈项目中常用的MySQL优化方法,共19条,具体如下:1.EXPLAIN命令做MySQL优化,我们要善用EXPLAIN查看SQL执行计划.下面来个简单的示例,标注(1.2.3.4.5)我们 ...
- 出师表(ENGLISH) 强烈打call啊~王洛勇是什么神仙英语
臣亮言:先帝创业未半而中道崩殂, Permit me to observe: the late emperor was taken from us before he could finish his ...
- hbase 待看代码
flush split mvcc rpc get put mutation netty reactor模型 page cache 缓存 I/O 又被称作标准 I/O,大多数文件系统的默认 I/O 操 ...
- 安卓访问https错误,访问http可以,可能是nginx ssl证书配置有问题
开发中遇到react-native生成的android访问UAT和开发环境的http api都可以,但是访问生产环境的https就报错,还有就是第三方webhook调用你https网站的api也可能会 ...
- 2019-09-16 PHP CURL CURLOPT参数说明(curl_setopt)
CURLOPT_RETURNTRANSFER 选项: curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); 如果成功只将结果返回,不自动输出任何内容. 如果失败返回F ...
- vue项目开发遇见bug
1.附件的点击问题,与原生交互的问题: 原生的调用对象和vue的调用对象不同,注意原生方法的位置. 2.10.2以下fetch请求数据的问题(检查是否可以使用 can i use) 10.2以下ios ...
- 监控微信小程序中的慢HTTP请求
摘要: 请求时间太长,影响用户体验,使用 Fundebug 监控慢请求. Fundebug 的微信小程序监控插件在 0.5.0 版本已经支持监控 HTTP 请求错误,在小程序中通过wx.request ...