托管程序与非托管程序的区别

介绍托管程序与非托管程序的区别

本文主要介绍托管程序与非托管程序的概念,以及两者之间的区别。希望对你有帮助,一起来看。

AD:【线下活动】三大新锐HTML 5企业汇聚51CTO—大话移动前端技术

托管代码是一microsoft的中间语言,他主要的作用是在.NET FRAMEWORK的CLR执行代码前去编译源代码,也就是说托管代码充当着翻译的作用。下面介绍托管代码非托管代码。

什么是托管代码?

托管代码就是Visual Basic .NET和C#编译器编译出来的代码。编译器把代码编译成中间语言(IL),而不是能直接在你的电脑上运行的机器码。中间语言被封装在一个叫程序集 (assembly)的文件中,程序集中包含了描述你所创建的类,方法和属性(例如安全需求)的所有元数据。这个程序集是.NET世界中的一个一站式购物 (译者注:就是程序集具有自描述性)部署单元。你可以拷贝这个程序集到另一台服务器上部署它--通常来说,这个拷贝的动作就是部署流程中唯一的一个操作。

托管代码在公共语言运行库(CLR)中运行。这个运行库给你的运行代码提供各种各样的服务,通常来说,他会加载和验证程序集,以此来保证中间语言的 正确性。当某些方法被调用的时候,运行库把具体的方法编译成适合本地计算机运行的机械码,然后会把编译好的机械码缓存起来,以备下次调用。(这就是即时编 译)

随着程序集的运行,运行库会持续地提供各种服务,例如安全,内存管理,线程管理等等。这个程序被“托管”在运行库中。

Visual Basic .NET和C#只能产生托管代码。如果你用这类语言写程序,那么所产生的代码就是托管代码。如果你愿意,Visual C++ .NET可以生成托管代码。当你创建一个项目的时候,选择名字是以.Managed开头的项目类型。例如.Managed C++ application。

什么是非托管代码?

非托管代码就是在Visual Studio .NET 2002发布之前所创建的代码。例如Visual Basic 6, Visual C++ 6, 最糟糕的是,连那些依然残存在你的硬盘中、拥有超过15年历史的陈旧C编译器所产生的代码都是非托管代码。托管代码直接编译成目标计算机的机械码,这些代 码只能运行在编译出它们的计算机上,或者是其它相同处理器或者几乎一样处理器的计算机上。非托管代码不能享受一些运行库所提供的服务,例如安全和内存管理 等。如果非托管代码需要进行内存管理等服务,就必须显式地调用操作系统的接口,通常来说,它们会调用Windows SDK所提供的API来实现。就最近的情况来看,非托管程序会通过COM接口来获取操作系统服务。

跟Visual Studio平台的其他编程语言不一样,Visual C++可以创建非托管程序。当你创建一个项目,并且选择名字以MFC,ATL或者Win32开头的项目类型,那么这个项目所产生的就是非托管程序。

这样子会导致一些混淆:当你创建一个托管的C++程序,那么构建出来的是一个中间语言程序集和一个扩展名为.exe的可执行文件。当你创建一个 MFC程序,构建出来是一个Windows原生代码的可执行文件,这个文件的扩展名也是.exe。这两个文件的内部结构是完全不一样的。你可以用中间语言 反汇编器(ildasm)来查看程序集的内部以及中间语言的元数据。如果尝试用中间语言反汇编器来查看一个非托管可执行文件,那么改反汇编器会告诉你这个 可执行文件没有包含一个合法的CLR头,所以不能被反编译。可见,这两个文件虽然有相同的扩展名,但是它们是完全不一样的。

原生代码又是什么呢?

原生代码这个短语可以用在两个不同的上下文中。很多人会把原生代码跟非托管代码看作是同一个意思:用较老的工具构建的代码,故意采用Visual C++并使直接运行在计算机上,而且不运托管在运行库中。这可以是一个完整的程序,或者是一个COM组件,又或者是一个可以被托管代码利用COM Intero或者平台调用(PInvoke)所调用的DLL文件,COM Intero或者平台调用(PInvoke)可以帮助你在迁移到新的技术平台下依然能重用老代码的两个强大工具。

我更愿意说是非托管代码,因为这强调的是那些不能利用运行库所提供的服务的代码。例如在托管代码中,代码访问安全服务可以防止在另一个服务器上装载的代码运行特定的操作。如果你的代码运行的是非托管代码,那么你没法利用这样的保护服务。

原生代码的另一个意思是描述即时编译器的输出,那些实际上运行在运行库中的机械码。这些代码是托管代码,但是并不是中间语言,而是机械码。所以不要简单地假设原生就是等同于非托管。

托管代码就意味着托管数据?

对于Visual Basic和C#来说,生活是简单的,因为你没有其它选择。当你在那些语言里面声明一个类,那么这个类的实例会在托管堆中被创建,垃圾收集器(GC)会帮 我们管理这些对象的回收。但是在Visual C++中,你有另一个选择。即使你正创建一个托管程序,你可以决定哪些类是托管类型,哪些类是非托管类型的。

这就是非托管类型:

  1. class Foo
  2. {
  3. private:
  4. int x;
  5. public:
  6. Foo(): x(0){}
  7. Foo(int xx): x(xx) {}
  8. };

这就是托管类型

  1. __gc class Bar
  2. {
  3. private:
  4. int x;
  5. public:
  6. Bar(): x(0){}
  7. Bar(int xx): x(xx) {}
  8. };

他们唯一的区别就是类Bar的定义中有__gc关键字。这个关键字会给代码带来巨大的区别。

托管类型是可以被垃圾回收器所回收的。他们必须要用关键字new来创建,永远都不会在栈中出现。所以下面这行代码是合法的:

  1. Foo f;

但是这一行代码就是非法的:

  1. Bar b;

如果我在堆中创建一个Foo对象,那么我必须要负责清理这个对象:

  1. Foo* pf = new Foo(2);
  2. // . . .
  3. delete pf;

C++编译器实际上会用两个堆,一个托管堆和一个非托管堆,然后通过对new操作符的重载来实现对创建不同类型类的实例,分配不同的内存。

如果我在堆里面创建一个Bar实例,那么我可以忽略它。当没有其他代码在使用它的时候,垃圾回收器会自动清理这个类,释放其占用的资源。

对于托管类型会有一些约束:它们不能实现多重继承,或者继承与非托管类型;它们不能用friend关键字来实现私有访问,它们不能实现拷贝构造函 数。所以,你有可能不想把你的类声明为托管类型。但是这并不意味着你不想让你的代码成为托管代码。在Visual C++中,你可以选择。

托管和非托管资源,是C#中的事,就不在这讨论了。

托管代码与非托管代码的性能比较

基本上每个人都知道的是,所有.Net语言都将被编译成为一个叫做IL汇编的中间语言。但是计算机是如何执行这个中间代码的,却是很多人不知道,甚至理解错误了的。

JIT是.NET程序运行的重要部件之一,全称是即时编译器。我刚才说的误解,就是很多人(绝对不是少数,问了很多c++程序员,10个有9个这种
想法)都以为JIT其实就是跟Java
VM差不多的东西,是一个Interpreter,在运行时读取IL汇编代码,然后模拟成x86代码(也就是俗称的虚拟机)。但是事实上,.NET使用的
是更为高级的技术。
.Net程序被加载入内存以后,当某段IL代码被第一次运行的时候,JIT编译器就会将这段IL代码,全部编译成本地代码,然后再执行。这也就是为什
么.NET程序第一次运行都启动很慢的原因!

随.NET库,微软还附带了一个工具,可以事先将.NET程序所有的IL代码都编译成本地代码并保存在缓存区中,这样一来,这个程序就跟c++编译
的一模一样了,没有任何区别,运行时也可以脱离JIT了(这里不要混淆了,这里不是说可以脱离.NET库,而是说不需要在进行即时编译这个过程了)。所
以,请不要将.NET和Java混为一谈,两个的运行效率根本不是一个等级的!

JIT的优化指的是可以针对本地CPU,在编译时进行优化。传统程序在编译时,为了保证兼容性,通常使用最通用的指令集(比如古老的386指令集)来编译。而JIT知道CPU的具体类型,可以充分利用这些附加指令集进行编译,这样的性能提升是很可观的。

时间: 2024-10-13 10:16:08

托管程序与非托管程序的区别的相关文章

编写高质量代码改善C#程序的157个建议——建议50:在Dispose模式中应区别对待托管资源和非托管资源

建议50:在Dispose模式中应区别对待托管资源和非托管资源 真正资源释放代码的那个虚方法是带一个bool参数的,带这个参数,是因为我们在资源释放时要区别对待托管资源和非托管资源. 提供给调用者调用的显式释放资源的无参Dispose方法中,调用参数是true: public void Dispose() { //必须为true Dispose(true); //省略其他代码 } 这表明,这时候代码要同时处理托管资源和非托管资源. 在供垃圾回收器调用的隐式清理资源的终结器中,调用的是false:

[转]在C#中使用托管资源和非托管资源的区别,以及怎样手动释放非托管资源:

托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等.这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法.默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源. 在

托管资源和非托管资源

在.net 编程环境中,系统的资源分为托管资源和非托管资源. 对于托管的资源的回收工作,是不需要人工干预回收的,而且你也无法干预他们的回收,所能够做的只是了解.net CLR如何做这些操作.也就是说对于您的应用程序创建的大多数对象,可以依靠 .NET Framework 的垃圾回收器隐式地执行所有必要的内存管理任务.        资源分为两种,托管的内存资源,这是不需要我们操心的,系统已经为我们进行管理了:那么对于非托管的资源,这里再重申一下,就是Stream,数据库的连接,GDI+的相关对象

.net 资源释放(托管资源和非托管资源)

1.托管资源 像int.float.DateTime等都是托管资源:net中80%的资源都是托管资源: 托管资源的回收通过GC(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我们无法控制系统在什么时间回收资源. 2.非托管资源 像ApplicationContext,Brush,Component,ComponentDesigner,Container,Context,Cursor,FileStream,Font,Icon,Image,Matrix,Object,Odbc

C#内存管理之托管堆与非托管堆( reprint )

在 .NET Framework 中,内存中的资源(即所有二进制信息的集合)分为“托管资源”和“非托管资源”.托管资源必须接受 .NET Framework 的 CLR (通用语言运行时)的管理(诸如内存类型安全性检查),而非托管资源则不必接受 .NET Framework 的 CLR 管理.(了解更多区别请参阅 .NET Framework 或 C# 的高级编程资料)托管资源在 .NET Framework 中又分别存放在两种地方:“堆栈”和“托管堆”(以下简称“堆”):规则是,所有的值类型(

C# 托管资源与非托管资源

在.net 编程环境中,系统的资源分为托管资源和非托管资源. 托管资源: Net平台中,CLR为程序员提供了一种很好的内存管理机制,使得程序员在编写代码时不要显式的去释放自己使用的内存资源(这些在先前C和C++中是需要程序员自己去显式的释放的).这种管理机制称为GC(garbage collection).GC的作用是很明显的,当系统内存资源匮乏时,它就会被激发,然后自动的去释放那些没有被使用的托管资源(也就是程序员没有显式释放的对象). 所以托管就是.net framework 负责帮你管理内

如何让IntPtr指向一块内存,以及托管内存与非托管内存的相互转化

IntPtr idp= IntPtr.Zero; StringBuilder idata = new StringBuilder("000000"); string idata ="000000"; 我这样建立的2个idata字符串,如何让idp指向他 我指向他的目的是为了传递给dll的某个函数,他需要传指针 还有我定义了一个结构如何向dll的函数传递其指针? 所有分了,解决一起结了 用GCHandle.Alloc(object obj)方法来给string分配一个

C# 托管资源和非托管资源

托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等.这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法.默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源. C

C# 托管内存与非托管内存之间的转换(结合Unity3d的实际开发)

1.c#的托管代码和非托管代码 c#有自己的内存回收机制,所以在c#中我们可以只new,不用关心怎样delete,c#使用gc来清理内存,这部分内存就是managed memory,大部分时候我们工作于c#环境中,都是在使用托管内存,然而c#毕竟运行在c++之上,有的时候,(比如可能我们需要引入一些第三方的c++或native代码的库,在Unity3d开发中很常见)我们需要直接在c#中操纵非托管的代码,这些non-managed memory我们就需要自己去处理他们的申请和释放了, c# 中提供