托管代码与非托管代码

托管代码就是中间语言(IL)代码,在公共语言运行库(CLR)中运行,编译器把代码编译成中间语言,由公共语言运行库环境(而不是直接由操作系统)执行的代码。托管代码应用程序可以获得公共语言运行库服务:内存管理,安全管理,线程管理,垃圾回收,类型检查等等。
 
托管代码是可以使用20多种支持Microsoft .NET Framework的高级语言编写的代码,它们包括:C#, J#, Microsoft Visual Basic .NET, Microsoft JScript .NET, 以及C++。所有的语言共享统一的类库集合,并能被编码成为中间语言(IL)。

下面先了解一下C#代码编译执行的过程:
在这里插入图片描述
由图片可以看出,编译器把代码编译成微软中间语言(IL),程序执行的时候再进一步将中间代码编译称机器码,而不是能直接在你的电脑上运行的机器码,所以在整个过程是需要进行两次编译才可以执行程序。源代码编译后的中间语言被封装在一个叫程序集的文件中,程序集中除了有托管代码外还包含了描述你所创建的类,方法和属性(例如安全需求)的所有元数据。
在托管执行环境中使用托管代码及其编译,可以避免许多典型的导致安全黑洞和不稳定程序的编程错误。同样,许多不可靠的设计也自动的被增强了安全性,例如 类型安全检查,内存管理和释放无效对象。
在这里插入图片描述
上图展示了编译后的程序集;
思考:那么托管代码真正执行的时候又是怎样的呢?

那下面讲一下托管代码的执行过程:
在这里插入图片描述
图中展示了一个方法的编译执行过程,托管代码首先经过JIT即时编译器编译成本地CPU指令,然后JIT再返回到CLR为类型创建的内部数据结构,再找到被调用函数的记录,修改JIT指令为本地CPU指令,再进行执行,这条CPU指令也会被存储在一块动态的内存中。
现在再看下面这张图片:

在这里插入图片描述
当二次调用同一个方法的时候,JIT编译器不会再进行编译,而是直接从刚刚的内存地址中直接调用执行,这样看来也编译器的效率会提升很多。但是当程序终止运行之后编译好的本地指令也将清空,再次启动的话还是需要通过即时编译器编译。

什么是非托管代码?  
非托管代码,直接编译成目标计算机码,在公共语言运行库环境的外部,由操作系统直接执行的代码,代码必须自己提供垃圾回收,类型检查,安全支持等服务。如需要内存管理等服务,必须显示调用操作系统的接口,通常调用WindowsSDK所提供的API来实现内存管理。

C#调用非托管代码:
DllImport

调用方法:

 [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);

属性介绍:

public class DllImportAttribute: System.Attribute
{
   public DllImportAttribute(string dllName) {}    //定位参数为dllName
   public CallingConvention CallingConvention;      //入口点调用约定
   public CharSet CharSet;                              //入口点采用的字符接
   public string EntryPoint;                //入口点名称,如果未指定EntryPoint,则使用方法本身的名称
   public bool ExactSpelling;    //是否必须与指示的入口点拼写完一致,默认false
   public bool PreserveSig;                 //方法的签名是被保留还是被转换
   public bool SetLastError;                //FindLastError方法的返回值保存在这里
   public string Value { get {} }
}

CallingConvention :
CallingConvention.Cdecl : 调用方清理堆栈。它使您能够调用具有 varargs 的函数。
CallingConvention.StdCall : 被调用方清理堆栈。它是从托管代码调用非托管函数的默认约定。
CallingConvention. Winapi,默认选项,在 Windows 上默认为 StdCall,在 Windows CE.NET 上默认为 Cdecl。

CharSet:
在这里插入图片描述
EntryPoint:
相当于是取了一个别名。下面的例子说明可以使用MsgBox调用 MessageBoxA

 [DllImport("user32.dll", EntryPoint = "MessageBoxA")]
  public static extern int MsgBox(int hWnd, String text, String caption, uint type);

ExactSpelling:
如果设置为true,会根据找相同的名字,例如,如果指定MessageBox,则平台调用将搜索 MessageBox,如果它找不到完全相同的拼写则失败。

SetLastError:
设置为true的时候,调用方法出现错误的时候会将错误信息存储,通过Marshal.GetLastWin32Error()可以获取错误码。

托管代码和非托管代码的区别:
1、托管代码是一种中间语言,运行在CLR上;非托管代码被编译为机器码,运行在机器上。

2、托管代码独立于平台和语言,能更好的实现不同语言平台之间的兼容;非托管代码依赖于平台和语言。

3、托管代码可享受CLR提供的服务(如安全检测、垃圾回收等),不需要自己完成这些操作;非托管代码需要自己提供安全检测、垃圾回收等操作。

对比托管代码和非托管代码的效率

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值