|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
据说很厉害,甚至可以把C#也干掉^_^,不过也很复杂,本来C++已经够复杂的。有人甚至还提出把这个东东引进标准,我觉得基本上不可能的。自打利用.Net以来,他给我的印象就一向是:慢。不外这几天看了一下.Net程序运转时的道理,才分明了我们平常的.Net程序是为何慢的,也分明了在某些情形下实在.Net程序运转起来也不比非托管程序慢。
要看托管程序慢的缘故原由,就得说说使用程序加载的历程。
使用程叙文件的格局是有纪律的。不论是托管程序仍是非托管程序,可实行文件的外部都包括一个PE文件(包括在exe文件大概dll文件的外部),体系也恰是依据PE文件内里的信息来启动这些可实行程序的。体系依据PE文件中的信息,找到出口函数,接着将把持调转到这个函数中,从而启动这个程序。不外托管程序的文件中另有一个CLR表头文件和其他CLR必要的信息。(有关PE文件的信息,请点击这里。团体以为要真正了解托管程序为啥慢,下工夫懂得PE文件及其感化仍是很主要的)
起首看看非托管程序。非托管程序的可实行文件都是二进制文件,是间接被编译成CPU指令的。在非托管程序的可实行文件中,编译器在编译的时分已把对办法的挪用间接编译成了CPU指令:由于在编译的时分就晓得办法在代码段里的绝对地点,也就是偏移量。当体系加载了可实行文件后,我们经由过程将可实行文件的基地点加上这个偏移量就能够盘算出办法在内存中的实践地点。如许只需经由过程这类办法修正JMP指令,就能够间接运转全部程序。
但托管程序分歧。由于托管程序编译的了局是IL两头代码,而这个IL代码是由CLR及时编译的,以是在启动这个程序之前,必需先加载CLR,并由CLR卖力处置IL代码中的办法挪用。
那末,操纵体系是怎样晓得一个使用程序必要加载CLR的呢?大概有人会说由于托管程序的文件中另有一个CLR头部,看到这个就晓得是托管程序。这个说法固然不合错误。最新的操纵体系大概可以认出CLR头部,但2000之前的体系,他们怎样会认得出CLR头部?要晓得当这些体系出来的时分,还基本没有CLR这个玩艺儿呢。
实践上,体系启动一个托管程序,最入手下手的步骤都是一样的:反省PE文件,然后实行PE文件中.text段(也就是代码段)中的代码。但托管程序在编译时,.text段内里增添了一条JMP_CorExeMain大概JMP_CorDllMain的指令(依据是exe文件仍是dll文件分歧)。也恰是从这里入手下手,托管程序的加载与非托管程序的加载发生了区分。这时候候假如长短托管程序,就已进进到出口函数中往了;但托管程序此时却跳转到了另外一个函数中。那末这个函数是那里的呢?这个函数在一个叫做MSCorEE.dll的静态链接库文件中,当安装了.net框架时就会被复制在体系目次下。体系会依据托管程序PE文件中的信息找到这个DLL,然后经由过程MSCorEE.dll的PE文件信息找到这个_CorExeMain函数的出口地点,然后修正方才的JMP指令要跳转的地点,从而将把持跳转到了_CorExeMain这个函数内里往。然后,在这个函数内里,CLR被启动了,并做了多少的初始化事情,然后再经由过程托管程序的CLR表头找到托管程序的出口地点,并将把持跳转到这里,因而托管程序入手下手运转。不外,上述历程在最新的操纵体系上分歧,由于这些新的操纵体系认得托管程序的标记(也就是说晓得依据PE文件中的标记往判别是不是是托管程序),因而在加载时就会间接挪用_CorExeMain,JMP指令间接被跳过的。
方才说了托管程序在启动时的一些特别处置:体系在进进出口函数前会起首挪用MSCorEE.dll中的代码来启动CLR并做一些初始事情,然后再进进出口函数。但另有个成绩没提到:那就是方才我们有说到托管程序的编译了局是IL代码,这个IL代码是在运转时被CLR及时编译的。那末,这个及时编译的历程又是如何的呢?
实践上,IL中的办法并非每次被挪用时城市被从头编译一次,而是就像我们平常接纳的“LazyLoad”一样,他只要在第一次被挪用的时分才会被编译。立即编译器保留有一个映照表。当挪用一个办法时,立即编译器假如发明在这个映照表中没有标志这个办法,就会将这个办法的IL代码编译成CPU指令,然后分派在一个内存空间上,然后在这个映照表中纪录下这个办法名和办法出口对应的内存地点,然后经由过程JMP指令跳转到函数中往。当下次再发生对这个办法的挪用时,立即编译器由于已晓得了这个办法对应的内存地点,因而就会间接经由过程JMP指令跳转,而不会再次编译这段代码。
因而能够看出,只需程序一切的代码都被实行过一次了,那末全部程序就城市被编译成CPU指令保留在内存中。在此以后托管程序跟非托管程序的实行效力就基础上没甚么区分了——固然,托管程序必要从谁人映照表中取函数地点,而非托管程序中办法的地点是已知的。
因而,实际上在某些情形下(好比winservice、iis等临时轮回实行的程序),托管程序的功能其实不会比非托管程序的功能差几。并且,非托管程序由于要思索兼容性必需兼容尺度指令,而非托管程序由于是运转时编译的,十分分明操纵体系情况,因而能够做针对性的优化。
不外,由于立即编译的了局是保留在内存中的,因而关于那些会频仍启动的程序来说,其启动历程是会对照慢的——由于每次启动都必要加载CLR并做一次立即编译。
至此,在懂得到了托管程序与非托管程序在加载、实行时的区分,我们就能够加倍分明如何才干充实使用非托管程序的长处、制止其弱点,从而发扬他的最年夜代价、制止利用时走进误区。
批评
#4楼2008-04-1708:27young5335[未注册用户]用NGEN.EXE天生后的速率是否是能快些?WINFORM程序,出格是利用了一些界面控件后,速率慢的让人没法忍耐。
NGEN天生的呆板码跟WIN32程序比拟,速率快仍是慢呢?#6楼2008-04-1708:30DaVinci道理对照简单了解可是要分明在某些情形下.NET程序纷歧定比其他的非托管的慢由于CLR会优化一部分代码的运转期历程这比Java要快多了乃至有些情形实行速率和非托管的C++差未几
#8楼2008-04-1708:32DaVinci@young5335
情形分歧速率也分歧一样平常来讲NGEN的呆板码不如JIT的速率由于优化不如JIT
#9楼2008-04-1708:38lbq1221119不错呵呵
体系怎样启动托管app,能够参考sscli团队内里的一篇的具体先容.
#10楼2008-04-1708:40lbq1221119也就是假如不利用ngen在第一次运转的时分必要便已成为nativecode.可是这个时分是做了良多的编译器优化,然后把了局存起来,今后常常利用的时分就快多了,一点也不比非托管的慢
#11楼2008-04-1708:42lbq1221119@DaVinci
ngen只是针对一套对照通用的cpu指令举行编译的,为了思索通用性.
jit有很对正对以后的特定平台的编译优化举措.
#13楼2008-04-1708:49DaVinci能够看看jeffer的那本书很具体的讲了
#14楼2008-04-1708:58gussing这个不是MSDN中的.net概论那一章嘛。
人人进修.net的时分,岂非连概论都不看的?
#18楼[楼主]2008-04-1709:26没有昵称@Justin
哈哈,偶技穷了呵。这东东专业术语蛮多的,我还真不晓得咋弄个普通点的工具形貌呵。
#21楼2008-04-1709:50..那末楼主你有无.Net的针对性优化计划?比如:托管程序预编译等..
#22楼2008-04-1709:55oweb[未注册用户]的确比其余都慢吗?#25楼2008-04-1711:00jipp.cn[未注册用户].Net程序一点多不慢,
#26楼2008-04-1711:09风海迷沙比起ASP来,ASP.NET已非常快了。
#27楼2008-04-1711:13发展的强强的确在良多情形下和别的言语的程序比起来都要慢些,,
#28楼2008-04-1711:17jipp.cn[未注册用户]方才忘了申明一点,运转快不快,决意要素在写程序的人,而不是工具,
#29楼2008-04-1711:27PerfectDesign说假话,假如你决心寻求速率,你能够不必面向对象的言语啊
开辟速率进步是为的呼应需求的变更,紧切市场的多变
假如你C开辟一年出来了,早就被减少失落了,还要干吗?
.net就是为的如今市场的需求应运而生的吧,可以满意尽年夜部分市场就乐成了。
没需要为了好比每秒几万并发量的网站来指责.net的速率
#30楼2008-04-1711:28RiversZhao.NET程序的确对照慢,但如今的机子愈来愈快,信任会办理的.但不论如何,一定比不上原生C/C++程序快
#31楼[楼主]2008-04-1711:29没有昵称@PerfectDesign
呵呵。懂得这些的缘故原由就是为了知其以是然,然后更好的发扬.net的优点、制止其弊端。仅此罢了。没有说发明他有点慢就不必。^_^
c有c的快,快在实行速率;.net有.net的快,快在开辟效力。
#32楼2008-04-1712:01AngelLucifer在跟Native言语一律前提下,我团体以为.NET的程序运转速率对照慢。这里不谈算法和计划。
Microsoft传播鼓吹其速率跟C++之类的Native言语速率比拟,能够到达其运转速率的98%(跟Java比,两个是势均力敌
)。可是团体体验,能到达90%已算是谢天谢地了。.NETBaseClassLibrary的编码偏向于以平安不乱为准绳,而不是功能。
好比针对2维数组的会见,利用指针来会见与利用索引来会见,功能差了10倍以上,整整一个数目级。运转时检测拖了年夜年夜的后腿。
一般有GC的言语,都必要年夜内存和年夜缓存才干表现其优秀的功能。可是年夜内存又会招致Cache射中率下降,还真难以弃取。
因为多核成为支流,.NET和Native言语的功能差异会慢慢缩减。由于此时体系功能瓶颈基本不在这里了。我们能够设想将来多核CPU的中心>=32时又会是一番甚么风景?
#33楼2008-04-1712:03DaVinciJava的运转期和编译期都慢C#编译期慢实行期纷歧定慢
#34楼2008-04-1712:06boyxia[未注册用户]应当和java比比。
#35楼2008-04-1712:07AngelLucifer援用--------------------------------------------------
DaVinci:Java的运转期和编译期都慢C#编译期慢实行期纷歧定慢
--------------------------------------------------------
@DaVinci
这番话有甚么根据没有?
据我所知,这两个都是基于VM的言语,功能上几近相称,不过就是这里你快点,那边我快点的区分。--
#36楼2008-04-1712:26DaVinci@AngelLucifer
Jvm.dll加载类库办法是class的字节码CLR的mscrolib.dll在assembly中有个当地的image(GAC中的是别的的),如许当地的版本加载以后会对照快一些团体感到请指教.
#37楼[楼主]2008-04-1712:36没有昵称@AngelLucifer
是啊,本来的指针指来指往的,给人感到十分爽。指针这玩艺儿在有些人手里会误伤本人,在别的一些人的手里就会能力非常。
.net为了把这个双刃剑酿成平安的,泯灭了良多功能上的工具来包管平安性。不外如今硬件的开展已能够填补这些了。楼上也有良多兄弟说.net不慢,不外在几年前的pc设置上,那叫一个疾苦啊。。。
实在会商这个成绩,也是为了给一部分程序员一个谜底:有些人会视.Net为祸不单行,提到.net就以慢为来由来抵抗。现实上那百分之几的功能不同,在今朝的年夜部分使用中都不是次要冲突。
#38楼2008-04-1712:45DaVinci@没有昵称
批准LZ概念指针实在也是双刃剑任何手艺使用欠好都是
#39楼2008-04-1713:08BlueMountain不外,由于立即编译的了局是保留在内存中的,因而关于那些会频仍启动的程序来说,其启动历程是会对照慢的——由于每次启动都必要加载CLR并做一次立即编译。
----------------------------------------------------------------
lz断定是在内存中么,c:windowsAssemblyGAC_32
c:windowsAssemblyNativeImages_v2.0.5XXXX
那些文件夹内里存的是甚么啊??
#40楼2008-04-1713:21DaVinci@BlueMountain
文件夹存的是程序集阿GAC中是共享程序集Assembly中的当地程序集的一个拷贝LZ说的是对的立即编译了局是在内存中JIT的事变
#41楼2008-04-1713:22李战途经,这里多数玩.NET的
楼主也不说和谁比,如许就有热烈看,高,其实是高!
#42楼[楼主]2008-04-1713:58没有昵称@DaVinci
帅哥太客套啦~~~java我不熟习,这个不分明呵。
偶如今还没来得及打仗java。我弄.net之前是弄VC的,一向都没离开windows平台。实在我的一些底层的常识也是在本来弄VC的时分学到的。^_^
底本盘算筹办进修一下java的源代码,不外由于要学的工具太多,还没入手下手呵。。
#43楼[楼主]2008-04-1713:59没有昵称@李战
和非托管程序比。不论是c、c++、vb、vc等等,他们天生的winapp的编译、加载历程都是一样的。
偶想说的重点是经由过程对照他们的加载历程和编译历程,懂得.net为啥这么慢,而不是对照谁快谁慢的成绩呵。^_^
#44楼2008-04-1714:19路人小刀[未注册用户]实践上,IL中的办法并非每次被挪用时城市被从头编译一次
----------------------------------------------------------------
难怪程序第一次运转时的速率,是云云让人末路火!
#45楼2008-04-1714:21路人小刀[未注册用户]托管程序此时却跳转到了另外一个函数中。那末这个函数是那里的呢?
1).这个函数在一个叫做MSCorEE.dll的静态链接库文件中,当安装了.net框架时就会被复制在体系目次下。
2).体系会依据托管程序PE文件中的信息找到这个DLL,
3).然后经由过程MSCorEE.dll的PE文件信息找到这个_CorExeMain函数的出口地点,
4).然后修正方才的JMP指令要跳转的地点,从而将把持跳转到了_CorExeMain这个函数内里往。
5).然后,在这个函数内里,CLR被启动了,并做了多少的初始化事情,
6).然后再经由过程托管程序的CLR表头找到托管程序的出口地点,并将把持跳转到这里,
7).因而托管程序入手下手运转
----------------------------------------------------------------
一共有七个步骤,挺成心思的
#46楼2008-04-1714:30年夜林[未注册用户].net算好了,之前编译过一JAVA的项目,居然编译了半小时才完成
#47楼[楼主]2008-04-1714:32没有昵称@路人小刀
收拾的很明晰哈。^_^
实在这内里的第六步,“将把持跳转到这里”之前,立即编译器必要把出口函数从IL代码编译成CPU指令,然后才干跳转已往。文章内里讲到这个的时分还没提到立即编译,事先就没指出呵。^_^
#48楼2008-04-1714:35justleo[未注册用户]实在程序慢的做要缘故原由仍是程序计划自己
#49楼2008-04-1714:45A.Z![未注册用户]--援用--------------------------------------------------
boyxia:应当和java比比。
--------------------------------------------------------
撑持
#50楼2008-04-1715:10随风逝往(叶进)知其以是然了,那该怎样变更,从而改善其实行速率呢?
#51楼[楼主]2008-04-1715:22没有昵称@随风逝往(叶进)
我以为,第一,可让程序少启动,不外这个合用局限不年夜;另外一个就是多用“提早加载”。
#52楼2008-04-1715:35DaVinci@随风逝往(叶进)
改善程序实行速率的办法有良多,算法,一些计划形式等等.针对程序自己道理而言也有良多,援用范例和值范例的计划,挪用,办法计划等等.总之看你详细怎样用.举一些例子就是在只管机关函数中初始化字段而不是在范例中初始化;制止装箱;提早加载也是;用is而不是强迫转型......良多
#53楼2008-04-1716:40birdshome通用的Framework历来不是为功能计划的
#54楼2008-04-1717:04BlueMountain不外,由于立即编译的了局是保留在内存中的,因而关于那些会频仍启动的程序来说,其启动历程是会对照慢的——由于每次启动都必要加载CLR并做一次立即编译。
----------------------------------------------------------------
lz断定是在内存中么,c:windowsAssemblyGAC_32
c:windowsAssemblyNativeImages_v2.0.5XXXX
那些文件夹内里存的是甚么啊??
复兴援用检察删除修正
----------------------------------------------------------------
@BlueMountain
文件夹存的是程序集阿GAC中是共享程序集Assembly中的当地程序集的一个拷贝LZ说的是对的立即编译了局是在内存中JIT的事变
复兴援用检察
上面这个图,我想晓得gac内里的是assembly,那末gac_32呢gac_msil呢nativeimages_XX呢感到它们仿佛是存的镜像阿jit编译的了局仅能存在内存内里么?如许子也不免太笨了吧ngen天生的又是存在甚么中央的呢
<br>
#55楼2008-04-1717:17Mainz
看和谁对照了,和汇编,C,C++比,固然慢了;和java比就纷歧定了。
我以为最好是中心算法用C或C++包管效力,其他的用C#,取长补短,效果最好
#56楼2008-04-1717:23222[未注册用户].net也只配和java比比了
#57楼2008-04-1717:33DaVinci@BlueMountain
GAC_32是JIT编译的针对32bit呆板的程序集假如是64位的话在syswow路径上面也能找到.由于GAC_32是.NET2.0引进的,它与GAC的区分是GAC下的是.NET1.1的程序集,GAC_32只是.NET2.0的程序集,没有.NET1.1的.
GAC.MSIL内里是一些轻量级的程序集
这些都是32位呆板才有,64位就一个GAC_64
ngen.exe和这些不妨,看你编译的参数,假如你是公有程序集,就是你本人指定的路径阿
#58楼2008-04-1718:05研讨者[未注册用户]你应当多看看相干的材料再来讲这个事变!!!!!!
#59楼2008-04-1718:06研讨者[未注册用户]不晓得它的事情机制就不要在此宣布行动,OK?
#60楼2008-04-1718:09BlueMountain@DaVinci
就是说jit编译的了局切实其实是仅仅在内存中的,多谢!
#61楼2008-04-1719:38GoGoSonnyVC6第一次启动快,但VS20052008下一次启动快!
比C++,有优势,但也有上风。
关于JAVA,.NET没的说。
关于剧本,庞大的.NET有上风。
#62楼2008-04-1721:36techmango[未注册用户]有这么庞大吗?!看了头晕啊
#63楼[楼主]2008-04-1722:20没有昵称@研讨者
er,,,我的确是细心的看了两资质料确认了以后才写出来的啊。
不外假如帅哥以为我说的不合错误,你能够告知我错在那里么?我也好持续进修。
#64楼[楼主]2008-04-1722:51没有昵称呵呵,,,仿佛良多伴侣在这里研讨起来谁快谁慢的成绩了,呵呵,切题了切题了。
不外,既然这个成绩这么敏感,那我就特地贴两个地点,列位能够看一下这位仁兄在碰到成绩的时分是如何处置的。
先看这个:http://www.ckuyun.com/wuchang/archive/2006/12/07/584997.html
再看这个:http://eparg.spaces.live.com/blog/cns!59bfc22c0e7e1a76!2274.entry
这位仁兄的做法很值得我们思索。他在发明成绩的时分第一反响是往剖析成绩找缘故原由,并终极扒开迷云找到了事变的原形。信任也恰是如许的探究精力让这位仁兄成为一个年夜牛的。
#66楼2008-04-1810:01Anytao增补:MSCorEE.dll中的代码来启动CLR并做一些初始事情,这些初始化次要包含:
1创立内存;
2创立线程池;
3创立使用程序域名。
关于功能,.NET实在已有良多优化战略,其主动内存办理上有诸多的优化机制,比拟原生态的C代码来讲在某些方面乃至体现更优。不论如何,如今是托管情况的时期,我们更加的懂得托管情况,也就可以更好的把持功能。来自:http://www.ckuyun.com/ILove/archive/2008/04/17/1157229.html中间码是基于一个虚拟机器。源代码是最高层的,理论上从源代码开始直接编译成本地码能提供最大优化的。而中间码只能是转译成本地码,效率上难免受到损耗。根据虚拟机器所设定的体系结构的特点,和本地机器的差异的多少。 |
|