编程中的托管代码和非托管代码是什么?

177

我在我的C#代码中使用了一个特定的命令,它运行良好。然而,据说它在“非托管”代码中表现不佳。

什么是托管或非托管代码?


13个回答

228

这篇文章是关于这个主题的好文章。

总结一下:

  1. 托管代码不会被编译成机器码,而是被编译成中间语言,由计算机上的某个服务解释和执行,因此在(希望如此!)安全的框架内运行,处理像内存和线程等危险的事情。在现代用法中,这通常意味着.NET,但并非必须。

在安装在同一台计算机上的运行时引擎中执行的应用程序。没有它,应用程序无法运行。运行时环境提供程序使用的通用软件库以及通常执行内存管理。它还可以提供即时(JIT)从源代码到可执行代码或从中间语言到可执行代码的转换。Java、Visual Basic 和 .NET 的公共语言运行时 (CLR) 是运行时引擎的例子。(阅读更多

  1. 非托管代码被编译成机器码,因此直接由操作系统执行。因此,它具有托管代码无法实现的破坏性/强大的功能。这就是旧版本中.dll等文件的工作方式。

一个可以自行运行的可执行程序。从操作系统启动,程序调用并使用操作系统中的软件例程,但不需要使用另一个软件系统。已经汇编成机器语言的汇编语言程序和为特定平台编译成机器语言的C/C++程序是非托管代码的示例。(阅读更多

  1. 本地代码通常与非托管代码同义,但并非完全相同。

你的意思是在黑客攻击中不能使用.NET语言(如C#,C ++),对吗? - Haroon A.
8
“H_wardak,您如何定义‘黑客’这个词?它是一个非常泛化的术语,就好像说黑客入侵NORAD和黑客入侵某些注册表是一样的。” - Alex
7
有一次面试官问我,在C#中能否运行/编写非托管代码?有人可以帮忙解答吗? - RSB
10
@RSB:在C#中你不能编写非托管代码(但你可以直接从C#调用非托管代码)。理论上,如果使用正确的编译器和框架,应该是可以做到的。然而,在实践中,这意味着你需要一个能够将C#编译为机器码的编译器。不确定如何实现这一点。 - James Haug
1
@JamesHaug 现在你可以使用 unsafe 关键字了。 - Mike Lowery

80

这是来自MSDN关于非托管代码的一些文本。

某些库代码需要调用非托管代码(例如,Win32之类的本机代码API)。由于这意味着要超出受托管代码的安全边界,因此需要谨慎对待。

以下是有关托管代码的其他补充说明:

  • CLR执行的代码。
  • 针对.NET Framework基础结构——公共语言运行时的代码称为托管代码。
  • 托管代码提供了CLR所需的元数据,以提供诸如内存管理、跨语言集成、代码访问安全和对象自动生命周期控制等服务。基于IL的所有代码都作为托管代码执行。
  • 在CLI执行环境下执行的代码。

针对你的问题:

我认为这是因为NUnit会执行你的代码进行单元测试,可能其中的某个部分是非托管的。但我不确定,所以不要完全相信这一点。我相信有人能够给你更多的信息。希望能帮到你!


14
我很感激你所做的努力来回答我的问题。但是,那些不知道什么是“托管代码”的人将会对你在回答中所说的“库代码”、“非托管代码”、“本机代码API”、“CLR”、“.net框架的基础”、“IL”、“CLI执行环境”等等概念感到困惑。 - BenKoshy

70

当你想到非托管时,就应该想到与机器特定、机器级别的代码。例如x86汇编语言。非托管(本地)代码被编译和链接以直接在设计它的处理器上运行,暂时排除所有操作系统的东西。它不可移植,但速度非常快。非常简单,剥离了很多代码。

托管代码包括从Java到旧版解释性BASIC或任何在.NET下运行的内容。托管代码通常被编译为中间级P-Code或字节码指令集。这些指令与机器无关,虽然看起来类似于汇编语言。托管代码隔离程序与其运行的机器之间,并创建一个安全边界,在其中所有内存都是间接分配的,一般来说,您不能直接访问机器资源,如端口、内存地址空间、堆栈等。其想法是在更安全的环境下运行。

要将托管变量转换为非托管变量,例如,必须获取实际对象本身。它可能会包装或盒装在其他包装中。在32位机器上,非托管变量(例如'int')需要正好4个字节,没有开销或额外的包装。从托管代码到非托管代码的转换 - 再返回 - 称为"封送"。它允许您的程序跨越边界。


1
那么,编组如何与值类型和引用类型交互?例如,我记得看到过关于MarshalByRefObject的内容。 - Kyle Baran

25

尽可能简短地说:

  • 托管代码 = .NET 程序
  • 非托管代码 = "普通" 程序

23
.NET程序不是“正常”的吗? - jtate
2
@jtate - 这有点过于简化了,是的。 :) 我试图使它更加直观。无论如何,那已经是8年前的事了。今天,随着众多编程语言在日常使用中变得普遍,这种区分确实更加不精确了,是的。 - Vilx-

16

托管代码是由C#.Net、VB.Net、F#.Net等编译器创建的。它在CLR上运行,CLR提供垃圾回收、引用检查等服务,以及更多功能。因此,可以理解为我的代码由CLR进行管理。

另一方面,非托管代码直接编译成机器码。它不由CLR进行管理。


4
托管代码: 在与公共语言运行时的“合作协议”下运行的代码。托管代码必须提供元数据,以便运行时提供诸如内存管理、跨语言集成、代码访问安全性和对象自动生存期控制等服务。基于 Microsoft 中间语言 (MSIL) 的所有代码都作为托管代码执行。
非托管代码: 在不考虑公共语言运行时的约定和要求的情况下创建的代码。非托管代码在公共语言运行时环境中以最少的服务方式执行(例如,没有垃圾回收、有限的调试等)。
参考: http://www.dotnetspider.com/forum/11612-difference-between-managed-and-unmanaged-code.aspx

4
  • 托管代码:使用.NET语言编写的代码,例如C#、VB.NET。
  • 非托管代码:不是用.NET语言编写的代码,MSIL无法理解它并且不能在CLR下运行;例如我们在.NET应用程序中使用的第三方控件,这些控件不是用.NET语言创建的。

4

基本上,非托管代码是指不运行在.NET CLR(即不是VB.NET、C#等)下的代码。我猜测NUnit有一个运行器/包装器,它不是.NET代码(即C++)。


3
NUnit会在一个单独的AppDomain中加载单元测试,并且我认为入口点不会被调用(可能不需要),因此入口程序集为空。

2

托管代码运行在CLR即.NET运行时环境中。简而言之,所有的IL代码都是托管代码。但如果你使用一些第三方软件,比如VB6或VC++组件,它们就是非托管代码,因为.NET运行时环境(CLR)无法控制语言源代码的执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接