JIT-կոմպիլյացիա (անգլ. just-in-time compilation), դինամիկ կոմպիլացիան (անգլ. dynamic translation) ծրագրի կատարման ժամանակ արված կոմպիլյացիա է՝ այլ ոչ թե մինչև ծրագրի կատարումը։ Շատ հաճախ այն բաղկացած է մեքենայական կոդի թարգմանությունից, բայց կարող է վերաբերվել նաև այլ ֆորմատի թարգմանությանը։

Դինամիկ թարգմանչի հաջորդականությունը

JIT-կոմպիլյացիան մեքենայական կոդը թարգմանելու երկու ավանդական գաղափարների կոմբինացիա է՝ AOT-կոմպիլյացիա և ինտերպրետացիա, և իր մեջ համատեղում է երկուսի որոշ առավելություններ և թերություններ։ Կոպիտ ասած, JIT-կոմպիլյացիան համատեղում է կոմպիլյացված կոդի արագությունը ինտերպրետացիայի ճկունության հետ, ինտերպրետատորի հավելյալ ծախսերի հետ և լրացուցիչ կոմպիլյացիայի ծախսերը (ոչ միայն ինտերպրետացիայի)։ JIT-կոմպիլյացիան դինամիկ կոմպիլյացիայի տեսակ է, այդպիսով JIT-կոմպիլյացիայի տեսությունում կարող է տալ ավելի արագ կատարում քան ստատիկ կոմպիլացիան։ Ինտերպրետացիան և JIT-կոմպիլյացիան հատկապես համապատասխանում են դինամիկ ծրագրավորման լեզուների համար, այդ դեպքում runtime համակարգը կարող է կարգավորել late-bound տվյալների տիպերը և երաշխավորել կատարման անվտանգությունը։

Դինամիկ կոպիլյացիայի դասկարգումները

Իրականցման առանձնահատկությունները խմբագրել

JIT-կոմպիլյացիան կարող է կիրառվել ինչպես ամբողջ ծրագրում, այնպես էլ դրա առանձին մասերում։ Օրինակ տեքստային ձևախիչը (անգլ. text editor) կարող է կոմպիլյացնել ռեգուլյար արտահայտությունները տեքստի ավելի արագ փնտրման համար։ AOT-կոմպիլյացիայի հետ այդպիսի բան անել հնարավոր չէ, քանի որ տվյալները տրամադրում են ծրագրի կատարման ժամանակ, այլ ոչ թե կոմպիլյացիայի ժամանակ։

Նկարագրություն խմբագրել

 
Վիիտուալ մեքենայի միջավայրը՝ միջանկյալ ծրագրի բեռնման համար

Լեզուներում, ինչպիսին են Java, PHP, C#,Lua, Perl, GNU CLISP, սկզբնական կոդը թարգմանվում է միջանկյալ նկարագրության (անգլ. intermediate representation )՝ բայթկոդ անվանմամբ (անգլ. bytecode)։ Բայթկոդը ինչ-որ կոնկրետ պրեցոսսորի մեքենայական կոդ չի հանդիսանում և կարող է տեղափոխվել համակարգչի տարբեր ճարտարապետություն և իրականացվել նույն ձևով։ Բայթկոդը ինտերպրետացվում է կամ իրականցվում վիրտուալ մեքենայում ։ JIT կոպիլյատորը կարդում է բայթկոդի տարբեր բաժիներ (կամ ամբողջը միանգամից՝ հազվադեպ) և կոմպիլյացնում է մեքենայակն կոդի։ Այդ բաժիները կարող են լինել ֆայլեր, ֆունկցիաներ կամ կոդի ցանկացած հատված։ Կոդը կարող է կոմպիլյացված լինել, երբ այն պատրաստվում է կատարվել (այստեղից էլ "just-in-time" անունը)։ Մեկ անգամ կոմպիլյացված կոդը կարող է կեշավորվել և հետագայում կրկին օգտագործվել առանց վերակոմպիլյացայի (անգլ. recompile)։

Ի տարբերություն, ավանդական ինտերպրետացված վիրտուալ մեքենան (անգլ. interpreted virtual machine) ուղղակի ինտերպրետացնում է բայթկոդ, սովորաբար ավելի ցածր արդյունավետությամբ։ Որոշ ինտերպրետատորներ նույնիսկ ինտերպրետացնում են սկզբնական կոդը, բայթկոդի առանց սկազբանական կոմպիլյացիայի քայլի և նույնիսկ ավելի վատ արդյունավետությամբ։ Ստատիկ կոմպիլյացված կոդը (անգլ. Statically compiled code) կամ հարազատ կոդը (անգլ. native code) կոմպիլյացվում է նախքան տեղակայումը։

JIT մեթոդի հիմանակն նպատակը՝ ստատիկ կոմպիլյացիայի արդյունավետությանը հասնելը և գերազանցելն է, այդպիսով պահպանելով դինամիկ կոմպիլյացիայի առավելությունները՝

  • Ծանրաքարշ գործողությունների մեծամասնությունը, ինչպիսին է նախնական կոդի վերլուծությունը և հիմնական օպտիմիզացիաները հաճախ մշակվում են կոմպիլյացիայի ժամանակ, մինչև տեղակայումը՝ բայթկոդից մեքենայական կոդի կոմպիլյացիան շատ ավելի արագ է, քան կոմպիլյացիան սկզբնական կոդից։
  • Բայթկոդը փոխադրելի է, ի տարբերություն հարազատ կոդի կամ մեքենայական կոդի (անգլ.՝ native code
  • Միջոցը կարող է հսկել բայթկոդի կատարումը կոմպիլյացիայից հետո, այդ պատճառով այն կարող է գործարկվել ավազամանում ( անգլ.՝ Sandboxing, Ավազամանը համակարգչային անվտանգությունում հատուկ մշակված միջոց է, համակարգչային ծրագրերի անվտանգ կատարման համար)։
  • Պետք է նշել նաև որ հարազատ ծրագրերի համար ևս կա այդպիսի հնարավորություն, բայց տվյալ մեթոդի իրականցումը դժվար է։
  • Կոմպիլյացիան բայթկոդից մեքենայակն կոդի հեշտ է իրականցնել, քանի որ օպտիմիզացիայի աշխատանքի մեծամասնությունը արդեն արված է եղել կոմպիլյատորի կողմից։

JIT կոդը հիմանականում առաջարկում է ավելի լավ արդյունավետություն քան ինտերպրետատորը։ Դրանից բացի կարող է առաջարկել ավելի լավ արդյունավետություն քան ստատիկ կոմպիլյացիան, քանի որ շատ օպտիմիզացիաներ հնարավոր են միայն ծրագրի կատարման ժամանակ ՝

  • Կոմպիլյացիան կարող է իրականցվել անմիջապես նպատակային պրացեսսորի և օպերացիան համակարգի համար, որում գործարկվելու է հավելվածը։ Օրիանակ JIT-ը կարող է օգտագործել վեկտորային SSE2 պրոցոսսորի ընդլայնում, եթե գտնում է որ այդ պրոցեսսորը աջակցում է այն։ Սակայն մինչ դեռ JIT-ի հիմանակն իրականացում չկա, որտեղ այդ մոտեցումը կօգտագործվի, քանի որ պետք է օպտիմիզացիայի նման մակարդակ ապահովել, համեմատած ստատսիկ կոմպիլյատերի հետ, կպահանհանջվեր կամ ապպահովել բինար ֆայլ յուրաքանչյուր պալտֆորմի տակ, կամ միացնել օպտիմիզատորի մեկ գրադարան յուրաքանչյուր պալտֆորմի տակ։
  • Այդ միջոցը կարող է աշխատող ծրագրի մասին հավաքել վիճակագրություն և դուրս բերել օպտիմիզացիաներ հաշվի առնելով այդ ինֆորմացիաները։ Որոշ ստատիկ կոմպիլյատորներ կարող են նաև ընդունել մուտքային ինֆորմացիա։
  • Այդ միջոցը կարող է կատարել կոդի գլոբալ օպիմիզացիաներ (օրինակ՝ գրադարանային ֆունկցիաներ ներկառուցումը) առանց կորցնելու դինամիկ կոմպիլյացիայի առավելությունները և առանց հավելյալ ծախսերի՝ բնորոշ ստատիկ կոմպիլյատորին և լինկերին։
  • Կեշի ցանկալի օգտագործման համար կոդի ավելի հասարակ վերակառուցում։

Մեկնարկի հապավումը և օպտիմիզացիաները խմբագրել

JJIT կոմպիլյատորի տիպիկ հապավման պատճառը ծախսերն են բեռնման և բայթկոդի կոմպիլյացիայի վրա։ Ընդհանուր դեպքում, ինչքան լավ և ինչքան մեծ օպտիմիզացիաներ է կատարում JIT-ը, այնքան երկար է ստանում հապաղումը։ Այդ պատճառով JIT կոմպիլյատորը պետք է փոխզիջումներ կատարի գեներացված կոդի որակի և մեկնարկի ժամանակի միջև։ Սակայն, հաճախ ստացվում է այնպես, որ նեղ տեղերը (անգլ. bottleneck) կոմպիլյացիայի գործընթացում ստացվում է ոչ ինքը՝ կոմպիլյացիայի գործընթացը, այլ մուտքային և ելքային հապավումները (ինչպես օրինակ, rt.jar-ը Java Virtual Machine-ում (JVM) ունի 40ՄԲ չափ, և իրենում մետատվյալների փնտրումը զբաղեցնում է բավականչափ շատ ժամանակ)։

Այլ օպտիմիզացիայի միջոց է կոմպիլյացնել հավելվածի այն հատվածները, որոնք ավելի հաճախ են օգտագործվում։ Այդ մոտեցում է իրականցված է SunMicrosystems ընկերության PyPy -ում и HotSpot Java Virtual Machine -ում։


Երբեմն բավական դժվար է գտնել ճիշտ փոխզիջումներ։ Այդպես, օրինակ Sun’s Java Virtual Machine-ը ունի երկու աշխատանքի ռեժիմ՝ կլիենտ և սերվեր (անգլ. client and server) ։ Կլիենտի ռեժիմում կոմպիլյացիայի քանակը և օպտիմիզացիան մինիմալ են ավելի արագ բեռնման համար, մինչդեռ սերվերի ռեժիմում հասնում է մաքսիմալ արդյունավետության, բայց դրա պատճառով մեծանում է բեռնման ժամանակը։

Եվս մեկ մեթոդ, որը կոչվում է pre-JIT , կոդը կոմպիլյացնում է մինչև բեռնելը. տվյալ մեթոդի առավելությունը հանդիսանում է բեռնման ժամանակի արագությունը, մինչդեռ թերությունը հանդիսանում է վատ կոմպիլյացված կոդը runtime JIT -ի հետ համեմատած։

Հուսալիությունը խմբագրել

Քանի որ JIT կոմպիլյացիան բաղկացած է սկզբնական կոդի տվյալներից առաջանում է հուսալության (անվտանգության) հարց։

JIT կոմպիլյացիան իրենում համախմբում է սկզբնական կոդի կամ բայթկոդի կոմպիլյացիան մեքենայական կոդի և դրանց կատարումը։ Որպես կանոն արդյունքը գրվում է հիշողությունում և կատարվում է անմիջապես, չօգտագործելով դիսկ և չկանչելով առանձին ծրագիր։ Ժամանակակաից ճարտարապետությունում հուսալիությունը բարձրացնելու համար կամայական հիշողության հատվածները չեն կարող լինել իրականցված։ Ճիշտ աշխատանքի հաամար հիշողությունը պետք է նշված, որպես կատարվող (NX bit), ավելի մեծ անվտանգության համար ֆլագը պետք է դրված լինի հիշողության մեջ կոդի բեռնումից հետո, իսկ այդ հիշողությունը պետք է հասանելի լինի միայն ընթեցման համար։

Հղումներ խմբագրել