2009. december 18., péntek

A natív és menedzselt kód versenye

A .NET rendszer bevezetésének idején ádáz vita folyt arról, hogy vajon a menedzselt vagy a natív kód az, amelyik gyorsabban fut. Voltak, akik az egyikre, míg mások a másikra esküdtek. Sőt, számos mérési eredmény is közszemlére került. Főleg a C/C++ fejlesztők voltak azok, akik jókat nevettek azokon az állításokon, hogy egy menedzselt kód gyorsabb, mint a születésénél fogva natív kód. Ez a vita mára eldőlni látszik, mégpedig a menedzselt, JIT fordító által generált kódok javára. Ez igaz a Java és .NET kódra egyaránt .
Amikor egy C/C++ fordítóprogram előállít egy natív, futtatható fájlt (pl.: Windows alatt egy EXE-t), akkor különböző feltételezésekkel kell élnie, hogy a generálandó kódot majd milyen működési környezetre optimalizálja. Igyekszik az architektúra szerinti legkisebb közös többszörösnek megfelelő futtatható kódot előállítani. Azt azonban nem tudhatja, hacsak a programozó előre meg nem mondja neki, hogy ahol az a kód majd ténylegesen futni fog, hány processzor van, milyen a processzor és/vagy az adott hardver környezete, architektúrája, utasításkészlete, jellemző tulajdonságai, stb. Elképzelhető, hogy a programozó gépének tulajdonságai (ahol a futtatható kód előáll) gyökeresen eltérnek attól, ahol végül is a program majd futni fog.
Egy menedzselt kódnál a programozó, pontosabban fordítóprogram egy gép és architektúra független, köztes kódot állít elő még akkor is, ha a programozó fordítási időben ezt valamelyest befolyásolhatja. Később ezt a már említett .NET vagy Java szerinti gépfüggetlen kódot az adott számítógépen, ahol a futatás történik a JIT fordító fogja röptében végrehajtható, natív, gépi kódra fordítani. A lényeg az, hogy miközben a JIT fordító sorra veszi a köztes kód utasításait, azt is megnézi, hogy az a gép, ahol éppen működik, milyen architektúrával, utasításkészlettel rendelkezik, és ennek megfelelően képes az általa generált gépi kódot fordítás – vagy „jittelés” – közben optimalizálni. Másképp fogalmazva az adott végrehajtási környezetnek leginkább megfelelő futtatható kódot állít elő, ami gyorsabb lehet, mint egy adott környezetben (pl.: C/C++ fordítóval) már előre legenerált, futtatható kód. Ezen kívül a JIT fordító a natív kód generálása előtt képes kiszűrni és eltávolítani az olyan felesleges kódokat is, mint pl.: if(numberOfCpu > 1){...} vagyis a processzorok számának vizsgálatát akkor, ha az adott gépen csak egy processzor van. Ha pedig a gépbe mégis beletesznek egy újabb processzort, akkor a követező futtatásnál a „jitter” ezt már észleli, és a gépi kód előállításakor ennek megfelelően cselekszik.
Persze egy menedzselt kódnak nem csak előnyei, hanem hátrányai is vannak. Az egyik az, hogy a futtatható program első indulása meglehetősen lassú, hiszen a JIT fordítónak a köztes kódból le kell generálnia natív, futtatható, gépi kódot. Természetesen ez a művelet csak egyetlen egyszer hajtódik végre, hiszen amíg a program a maga natív, gépi kódú állapotában a memóriában van, addig azt többször már nem kell natív kóddá alakítania. A másik hátrány, hogy a program futása alatt a JIT által előállított natív kódot tárolni kell a memóriában, emiatt a fizikai memória helyfoglalása lényegesen nagyobb lehet, mint amit egy eleve natív, futtatható program esetén tapasztalunk. Fontos észben tartani, hogy a .NET rendszert „végtelen” nagy memóriára tervezték. Ez az elképzelés a mai átlagos RAM méret mellet (4GB) már nem is olyan naiv.

0 megjegyzés :

Megjegyzés küldése