托管代码和非托管代码,在内存和尺寸方面有何区别?

75

在了解了关于托管代码和非托管代码的许多信息后,我知道唯一的区别就是托管代码基于CLR,而非托管代码则在CLR之外。这让我真的很好奇,想详细了解一下。关于托管和非托管代码、内存和大小,到底是什么意思呢?

我写的C#代码怎么可能是非托管的,既然这是C#代码,内存大小又怎么变成了非托管的呢?举个例子并进行一些解释会很有帮助。


可能是以下问题的重复:C#中的托管/非托管代码是什么? - T.Todua
6个回答

155

简短回答:

  • 托管代码是您编写并编译为.NET CIL的.NET代码(VB.NET,C#等)。
  • 非托管代码是不在.NET下的编译为直接机器码的代码。

详细回答:

什么是托管代码?

托管代码是Visual Basic .NET和C#编译器创建的代码。它编译为中间语言(IL),而不是可以直接在计算机上运行的机器码。 CIL存储在一个称为程序集的文件中,其中包含描述您创建的代码的类,方法和属性(例如安全要求)的元数据。这个程序集是.NET世界中的一站式部署单位。将其复制到另一台服务器以在那里部署程序集-通常这是部署所需的唯一步骤。

托管代码在公共语言运行时中运行。运行时为您的运行代码提供各种服务。在通常的事件过程中,它首先加载和验证程序集以确保CIL没有问题。然后,在需要时,随着方法的调用,运行时会安排将其编译为适合运行程序集的机器码,并缓存此机器码以在下次调用该方法时使用。 (这称为即时编译,或JIT编译,或通常只是Jitting。)

随着程序集的运行,运行时继续提供安全性,内存管理,线程等服务。应用程序由运行时管理。

Visual Basic .NET和C#只能生成托管代码。如果您正在使用这些应用程序,则正在制作托管代码。如果您愿意,Visual C++ .NET也可以生成托管代码:创建项目时,请选择以“.Managed”开头的应用程序类型之一,例如“Managed C ++应用程序”。
什么是非托管代码?
在发布Visual Studio .NET 2002之前使用的即为非托管代码。Visual Basic 6、Visual C++ 6甚至那个15年前的C编译器(你可能还留在硬盘上)都会生成非托管代码。它直接编译成可在编译它的计算机上运行的机器码,并且在其他计算机上也可以运行,只要它们具有相同的芯片或几乎相同。它没有从不可见运行时获取安全性或内存管理等服务;它从操作系统中获取这些服务。重要的是,它通过请求来自操作系统显式地获得它们,通常通过调用Windows SDK中提供的API来实现。更近期的非托管应用程序通过COM调用获取操作系统服务。
与Visual Studio中的其他Microsoft语言不同,Visual C++可以创建非托管应用程序。当您创建一个项目并选择名称以MFC、ATL或Win32开头的应用程序类型时,您正在创建一个非托管应用程序。
这可能会导致一些混淆:当您创建一个.Managed C++ 应用程序时,构建产品是带有 .exe 扩展名的 CIL 程序集。当您创建一个 MFC 应用程序时,构建产品是本地代码的 Windows 可执行文件,也带有 .exe 扩展名。这两个文件的内部布局完全不同。您可以使用中间语言反汇编器 ildasm 查看程序集的元数据和 CIL。尝试将 ildasm 指向一个非托管 exe,您将被告知它没有有效的 CLR(公共语言运行时)头,无法进行反汇编-相同的扩展名,完全不同的文件。
原生代码怎么样?
短语原生代码在两个上下文中使用。许多人将其用作非托管代码的同义词:使用旧工具或故意选择 Visual C++ 中的代码,该代码不在运行时中运行,而是在计算机上本地运行。这可能是一个完整的应用程序,也可能是从托管代码使用 COM Interop 或 PInvoke 调用的 COM 组件或 DLL,这两个强大的工具确保您在转移到新世界时可以使用旧代码。我更喜欢用非托管代码来表示这个含义,因为它强调了代码不会获得运行时的服务。例如,托管代码中的代码访问安全性防止从另一个服务器加载的代码执行某些破坏性操作。如果您的应用程序调用从另一个服务器加载的非托管代码,您将无法获得此保护。
短语原生代码的另一种用法是描述 JIT 编译器的输出,实际在运行时中运行的机器代码。它是托管的,但不是 CIL,而是机器代码。因此,不要仅仅认为原生 = 非托管。

(来源)


我仍然对托管和非托管数据类型感到困惑。它们是否存在于当前的 .net 框架中? - Rajan Mishra
@RajanMishra 是的,它们存在。请查看此链接 https://dev59.com/tlQJ5IYBdhLWcg3wAA_z#54790777 - Shekhar Reddy

8
这可能是一个非常长的答案,涉及到 C 编译器生成的机器代码与 JIT 编译器从托管程序生成的机器代码之间许多细微差别。这足够长,需要一本书来解释,但这样的书已经写过了。例如 Jeffrey Richter 写的任何一本书。
我将保持简短有力,因为所有这些细微差别都归结为一个规则:
托管代码是从垃圾回收堆分配内存的代码。

2

托管代码运行在应用程序域中,非托管代码在操作系统的进程下运行。


1

非托管代码 :-

1.在.NET框架之外开发的代码称为非托管代码。

2.不受CLR控制的应用程序被称为非托管代码,某些语言如C++可用于编写此类应用程序,例如访问操作系统的低级功能。与VB、ASP和COM代码的背景兼容性是非托管代码的例子。

3.非托管代码通过包装器类执行。

4.包装器类分为两种类型:CCW(COM可调用包装器)和RCW(运行时可调用包装器)。

5.使用包装器来覆盖差异,其中CCW和RCW提供帮助。 管理代码 应用程序域内的资源是管理代码。域内的资源更快。

管理代码 1.在.NET框架中开发的代码称为管理代码。 该代码直接由CLR执行,借助于管理代码执行。任何在.NET Framework中编写的语言都是管理代码。

2.管理代码使用CLR,CLR负责管理内存、处理安全性、允许跨语言调试等。


1

通常情况下,托管代码的运行时内存占用比同等精良编写的非托管(本地)代码更高。


任何一个例子都可以说明托管代码和非托管代码之间的区别。 - Simsons
很难量化,因人而异 :). 然而托管代码需要开销。例如,运行时必须跟踪jit状态、垃圾回收,对象必须有元数据可用于反射等等。 - seand
那么我如何知道我正在编写的是托管代码还是非托管代码? - Simsons

-1

直接在操作系统下运行的应用程序称为

非托管应用程序

而在.net框架下运行的应用程序则被称为

托管应用程序


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