重新学.Net[四]——效率和安全

用.Net就不得不考虑效率问题(这点和Java一样),到底有没有这种性能问题?性能问题有多大?而微软一直声称托管程序是安全的,这种安全性到底是指的什么东西?达到这种安全到底付出了什么东西?我一直对这些问题很迷惑,最近看了一些书后有一些理解,仅仅是理解,欢迎大家来讨论。
要比效率,通常都是与C++相比。毫无疑问,除了极少的情况下,托管的程序与传统C++程序相比,效率有所降低,这种降低我个人觉得来源于以下几个方面:
1.就是从FCL的设计中看。FCL是完全面向对象设计的,它始终强到安全和异常处理。举个很简单的例子,C++的数组是一段连续的内存空间(栈或堆),而.Net(更严格说是CTS)中的数组是一个类(其实在定义上它是不同于类的一个引用型的东西,但其实不会有太多区别)。为了维护这个类的易操作性和更好的支持异常处理。在很多语言(以下就说C#)多做了很多其他工作。比如会默认初始化,在下标获取的时候会做越界的异常判断。这些都会耗费时间(C++中也有完全面向对象的库,这些库的情况也一样)。但是个人觉得,这部分效率,很多时候和使用场所,和编码者对所用语言的理解相关的。比如在需要为C++的数组初始化的场合要用赋值,效率还不如默认初始化。而在C#中,个人理解对效率也起到很重要的作用。比如为了满足非0初值的数组,有人会全部重新初始化,有人会取值然后加一个底数,根据场合不同,这两种方式的效率是不同的(考虑遍历和少数访问当情况)。再比如,在文件操作中有静态的File类和可实例化的FileInfo类。在反复对同一个文件进行copy的时候,我们应该选用FileInfo类,因为它只在实例化的时候进行异常检查,而静态的方法会每次操作都做这些检查。这样就降低了性能。总之,很多时候对类库的理解和正确使用会很大程度上影响的效率。C++不被好好的用也会写出很慢的程序。
2.JIT方式导致的性能损失。如果上面那部分有人的因素,那么这部分就几乎是天然的。JIT的性能损失可以从两个角度看,一个是第一次调用时会需要二次编译。这无疑会造成性能损失。但这种损失有时候是值得的,比如如果是一个新型的CPU,JIT可能更好利用其新的指令,编译出符合它特点的机器码,反而提升了性能(在框架程序一书中还列举了其他可能),这也就是有人说JIT方式理论上能超越C++程序性能的来源(至少不是不可能)。但总而言之,根据计算机程序的特点(通常会反复调用一些方法,80/20原理),JIT方式不会造成太大的性能损失。并且,如果你实在无法容忍,你可以NGEN提前编译成机器码再运行。但,很多时候是不推荐的。为什么不推荐这种方式呢?因为它会损失JIT的其它好处,就是安全性。JIT在编译中会做验证和安全性检查。所谓验证就是检查代码会不会跳出AppDomain的范围,避免了C++中一个不慎将指针指出界或者使用野指针造成的不可预知的错误。而安全性检查,指通过操作系统管理员的配置,可以控制JIT的权利。比如,不编译IO操作的代码,不允许其访问网络等等。与之相比,传统的程序一旦运行就无法控制(考虑一下,你运行了一个病毒exe,除了杀毒你还能干什么),而托管的程序,即使运行起来也可以控制(运行了又怎么样,不让你写我看你能干什么),从根源上堵住了恶意程序,这就是微软始终强调的安全性编码。只有应用JIT编译,才能实现(觉得很酷的方式,只要在操作系统中良好配置,就可以保证安全,很多防火墙软件以后估计要下岗了)。同样,这也需要损失一些性能,但是,如果你不需要,可以强行关闭(操作系统管理员的权利)。
3.最后是垃圾回收导致。因为垃圾回收会需要切换线程,打扰程序的运行。这部分性能我也不知道有多大的损失,总之微软说不大。
总之,托管的方式确实会造成一定的损失,但是这种损失在很多手段的运用下一步步减少。同时不要忘了,它提供了更安全的编码(比如在编码过程中,如果越界可以很快的发现,不会头痛不已)和运行方式。我觉得,在很多场合,也许这种性能的降低不会成为你用.Net编程的阻碍。

posted on 2007-02-07 16:39  duguguiyu  阅读(748)  评论(0编辑  收藏  举报

导航