Виртуални машини

I. Опростени дефиниции
II. Вариации във виртуалните машини
III. Програмни езици
IV. Особености

I. Опростени дефиниции

  • език - правила, определящи синтаксиса на текста, който ще се компилира до изпълним код. Самият текст се нарича изходен код. Може да е разпределен в един или повече текстови файлове.
  • компилатор - програма, която преобразува изходния код за даден език до изпълним код.
  • изпълним код - последователност от инструкции за реален (физически) процесор или за процесор на виртуална машина. Може да е в един файл (програма) или да е разпределен в няколко файла (програми, статични и/или динамични библиотеки). Файловете с изпълним код за .Net се наричат асемблита. В Java за всеки клас се създава отделен файл с изпълним код - class файл. Тези class файлове се архивират в jar (Java ARchive) файлове. Асемблитата и jar-овете съдържат т.нар. метаданни в допълнение към компилирания изпълним код.
  • виртуален процесор - програма, която интерпретира свой собствен изпълним код (виртуален код). Самият виртуален процесор се изпълнява на физически процесор и работата му е да превежда виртуалния си код до изпълним код за физическия процесор.
           В действителност разликата между кода за виртуалните и реалните процесори е голяма и не е възможно директно линейно съпоставяне на една виртуална инструкция към една реална. Често една инструкция във виртуалния процесор се свежда до много за реалния. Това превръща виртуалните процесори в един вид компилатори, които компилират виртуалния си код до код за даден реален процесор.
  • виртуална машина - система, състояща се от:
    • виртуален процесор
    • Garbage collector - "събирач на боклук", т.е. освобождава паметта, заета от обекти, които не се използват вече.
    • системи за защита, идентификация и оторизация при изпълнението на виртуалния код
    • система за динамично управление на кода (reflection)
    • базови библиотеки - с тяхна помощ програмистите могат да впрегнат в работа гореизброените неща. Често библиотеките се разглеждат отделно от предишните точки (наречени runtime). В този случай библиотеките се възприемат като програмен интерфейс за използване на runtime и се наричат framework. От такава гледна точка, виртуалните машини са съставени от две части - runtime и framework.
       Виртуалните машини, с които съм работил и за които ще пиша са Java и .Net. При работа с виртуални машини е важно да се изяснят термините и процесите на работа. Първо се пише изходният код, който се компилира до виртуален (managed) код. Този код се нарича байт-код за Java и MSIL (Microsoft Standard Intermediate Language) за .Net. За да се изпълни виртуалният код, той трябва да се сведе до native код (код за физическия процесор, на който се изпълнява виртуалната машина). Има два подхода за свеждане до native код (осъществени от виртуалния процесор):
  • Компилация по време на изпълнение (JIT) - позволява се по-голяма защита от неоторизирано изпълнение на потенциално опасен код. Освен това динамичното генериране и обработка на managed код (reflection) е възможно само в този вариант.
  • Предварителна компилация до native код - използва се заради по-бързото изпълнение.

II. Вариации във виртуалните машини

       Java е виртуална машина, която се поддържа за различни видове хардуери и операционни системи. Вариантите, в които се издава обхващат цялата виртуалната машина (не само основните библиотеки):
Виртуалната машина на Java се нарича Java VM (Virtual Machine).

       За разлика от Java, Microsoft поддържат .Net само за техните операционни системи (различните Windows-и). Изданията на .Net са много по-ограничени от тези на Java, защото обхващат само основните библиотеки (т.е. framework-а):
Виртуалната машина на .Net се нарича .Net CLR (Common Language Runtime). Макар и не поддържан от Microsoft, има проект за мултиплатформен .Net - Mono.

III. Програмни езици

       В началото Java обединяваше езика и виртуалната машина и съответно имаше компилатори само за езика Java (javac) и за мнемоничния код на виртуалния процесор (jasmin). След появата на .Net и неговата многоезичност, за Java също се създадоха компилатори за различни езици. В днешно време и двете виртуални машини имат "основни езици" - езикът Java за Java VM и езикът C# за .Net CLR. Тъй като основно за .Net се пише на два езика - VB (Visual Basic) и C#, то преобразуването на код между двата езика се налага често (има много код само на единия или само на другия език). За по-лесно преобразуване има сравнителни статии, а за по-мързеливите има и автоматични конвертори.
       Декомпилацията е характерна особеност и за двете виртуални машини. За Java се използва декомпилатор за езика Java (jad) и до мнемоничен код (jasper). За .Net се използва най-често Reflector (може да декомпилира до няколко от основните езици: MSIL, C#, Visual Basic, C++) и ILSpy (може да декомпилира само до MSIL и C#, но е безплатен).

IV. Особености

       Java е по-стара и има повече създаден код за нея (особено за Java Enterprise). Тя е мултиплатформена и се изпълнява на огромно разнообразие от хардуери (компютри, мобилни устройства, микроконтролери) и операционни системи. Като по-стара виртуална машина, Java е и по-модулна. Например Garbage collector-ът позволява да се изпълнява с различни алгоритми в зависимост от изискванията за запълване на паметта и за натоварване на процесора. Като по-нов, в .Net никога не е имало проблеми, които Java имаше доскоро или от които все още не се е отървала. Създаването на потребителски интерфейс в .Net е несравнимо по-лесно и самият интерфейс е по-лек и функционален. Все пак, макар и по-нов не може да се отрече, че .Net има доста трески за дялане. Паралелната обработка и синхронизациятя в Java е по-проста и по-удобна като остава напълно съпоставима от функционална гледна точка с .Net. Дизайн-тайм на .Net, който е заимстван от продукта Delphi на Borland, има проблеми, които Delphi не е имал.
       Взаимодействието с native код е различно - под Windows .Net има известно предимство, но от своя страна JNI (Java Native Interface) има и своите силни страни. В .Net има нещото наречено mixed-mode (managed-native) асемблита - съдържат едновременно managed и unmanaged код. Те могат да се пишат само на езика C++ (този език се поддържа от компилатора както за native, така и за managed код).
       За мултимедийни приложения Java предоставя библиотеката JMF (Java Media Framework), но поради ограниченията й често се използва и QuickTime for Java (обвивка на QuickTime API за Java). За .Net има managed обвивка на DirectX в самите SDK (за DirectX версия 9 и по-късни; преди нея се работи с COM Interoperation). За Media Foundation няма обвивка, но може да се направи.