当前位置: 欣欣网 > 码农

.NET9托管如何到非托管的?

2024-04-27码农

点击上方 蓝字 江湖评谈 设为关注/星标




前言

.NET代码全部都是托管的,托管在了CLR这个运行时上面。但是实际上真正的运行得靠非托管,计算机它不识别MSIL的二进制(参考: )。有没有想过如何从托管到非托管呢?本篇看下

详情

简单的例子:

staticMain(string[] args) { GC.Collect(); }

托管 意即C#代码,非托管意即C / C++/AS M 码。 这里以GC垃圾回收GC.Collect()为例,Collect函数毫无疑问是托管的。当你对Collect跟踪到时候,JIT会把整个MSIL加载到内存里面去,然后通过DebugInfo调试信息表定位当前断点的位置以及当前光标所在的位置。准确的让调试器停下来或者继续运行。

既然加载到内存,其实就很好理解了。Debug模式下通过DebugInfo来确定当前运行的堆栈轨迹,Release模式下其实也有调试信息,只不过删繁就简了。同样的通过DebugInfo来确定堆栈的运行轨迹。

代码:

extern"C"void QCALLTYPE GCInterface_Collect(INT32 generation, INT32 mode){ QCALL_CONTRACT; BEGIN_QCALL; _ASSERTE(generation >= -1); GCX_COOP(); GCHeapUtilities::GetGCHeap()->GarbageCollect(generation, false, mode); END_QCALL;}

GC.Collect通过QCall的模式进入到非托管之后,会调用C++代码,进行全代(如果Collect不指定某个代,就会对所有代进行GC)垃圾回收。一段托管代码/函数对应一个非托管的调用约定,双方约定俗成了如何进行通讯/调用的。

整体

整体性来说,Collect托管函数会被CLR加载,然后调用JIT进行Compile。最终Compile的结果里面包含了对于GCInterface_Collect非托管函数FCall的约定调用。如此基本上构成了托管-】非托管的运作过程。

往期精彩回顾