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

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

 

本文主要介绍托管程序与非托管程序的概念,以及二者之间的区别。但愿对你有帮助,一块儿来看。前端

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

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

什么是托管代码?编程

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

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

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

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

什么是非托管代码?编程语言

非托管代码就是在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的具体类型,能够充分利用这些附加指令集进行编译,这样的性能提高是很可观的。

相关文章
相关标签/搜索