Веб браузер с установленной виртуальной машиной java. Суть виртуальной машины Java


Дизайн JVM разрабатывался на основе многолетнего опыта программирования на таких языках как С и С++. Это позволило создать такую структуру JVM, которая сделала жизнь программиста значительно легче:

  • код приложения выполняется в контейнере,
  • в наличии защищённая среда выполнения программы,
  • уменьшилась до минимума возможность управления памятью программистом,
  • среду исполнения сделали кроссплатформенной,
  • стала использоваться рантайм (во время выполнения программы) информация для самоуправления.

Последний аспект позволяет JVM принимать более оптимальные решения при выполнении программы, основываясь на том как часто вызываются некоторые её блоки. Собственно виртуальная машина интерпретирует байт код скомпилированной джава программы, однако в JVM существует возможность компилировать часто вызываемые блоки программы в машинный код в рантайме. Эта технология называется Jast-in-time (JIT). Это не значит что машинный код сохранится в файл программы, он будет существовать только во время её выполнения в оперативной памяти. Таким образом производительность джава программы, после нескольких циклов работы, может стать выше чем у аналогичных программ компилируемых языков C и C++.

Что такое байткод?
Когда разработчики впервые знакомятся с JVM, они иногда думают о ней как о компьютере внутри компьютера. Поэтому можно легко представлять байткод как машинный код для процессора внутреннего компьютера или машинный код для выдуманного процессора.

Фактически байткод не очень похож на машинный код который будет запущен на реальном процессоре. Специалисты называют байткод промежуточным представлением, адаптацией между исходным кодом и машинным кодом.

Конечная цель байткода иметь такой формат представления данных и управляющей информации, что бы быть эффективно исполненным JVM.

Почему его назвали байткодом?
Код инструкции (opcode код операции) это только один байт (некоторые операции имеют параметры которые следуют за байтом операции в виде потока байт), таким образом существует только 256 вариантов инструкций. На практике некоторые не используются, остаётся примерно 200 используемых, но некоторые из них не были задействованы в последней версии javac.

Является ли компилятором javac?
Обычно компилятор создаёт машинный код, а javac создаёт байткод, непохожий на машинный код. Однако class файлы немного похожи на объектные файлы (как в Windows *.dll или Unix *.so) и являются нечитабельными.

В терминах компьютерных наук, javac наиболее похож на компилятор переднего плана, который создаёт промежуточное представление программного кода, из которого затем может быть создан машинный код.

Таким образом в чистом виде javac не компилятор, однако в большинстве книг и статей можно увидеть такие словосочетания - компилятор исходного кода или javac компилятор. А собственно компиляцией занимается JIT, когда создаёт машинный код для оптимизации выполнения программы.

Является ли байткод оптимизированным?
Ранние версии javac создавали сильно оптимизированный байткод. Это оказалось ошибочным. С появлением JIT компиляции более важным стало быстрое получение машинного кода. Поэтому оказалось, что нужно создавать такой байткод, который бы легко компилировался JIT. Поэтому сейчас имеется компромисс между оптимальностью байткода и быстротой его JIT компиляции. В свою очередь некоторая часть байткода продолжает оставаться интерпретируемой.

Является ли байткод действительно машинно независимым? Как на счёт порядка байт?
Формат байт кода всегда один и тот же, не важно на какой машине он был создан, это всегда big-endian (от старшего разряда к младшему). Например целое число занимающее в памяти 4 байта, хранится там побайтно от старших разрядов к младшим.

Является ли джава интерпретируемым языком?
По существу JVM это интерпретатор (с JIT компиляцией, которая даёт прирост производительности). Собственно исходный код джава не поступает интерпретатору на исполнение, он компилируется в байткод, а уже байт код интерпретируется JVM.

Могут ли другие языки выполнятся на JVM?
Всё что компилируется в байткод, может быть выполнено на JVM. Примеры таких языков - Scala, Clojure, Kotlin и т.д.
Кроме того, есть возможность реализовать интерпретатор некоторого языка на джава. Как это сделано, например, для языка JRuby.

Чтобы увидеть байт код, достаточно открыть файл.class в простом текстовом редакторе. Он окажется явно не читабельным. Однако у нас есть возможность дизассемблировать его в мнемоники байткода, то есть в элементарные команды (которые можно прочитать) и данные.

Рассмотрим простую программу складывающую два числа.

Public class Main { /** * Метод складывающий два числа. * @param a первое слагаемое * @param b второе слагаемое * @return результат сложения двух чисел. */ private static int adding(int a, int b) { return a + b; } /** * Точка входа в программу. * @param args неиспользуемые параметры командной строки. */ public static void main(String args) { // первое слагаемое int x = 43; // второе слагаемое int y = 56; // сложение значений двух переменных и помещение // результата в переменную. int result = adding(x, y); // вывод на экран значения переменной result. System.out.println(result); } }

Для удобства, можно создать пустой проект в Idea, и поместить этот класс в папку src.
Запустите его на исполнение. Idea скомпилирует его, естественно используя для этого javac, создаст файл Main.class и запустит его на исполнение. Проверим что у нас всё получилось, в консоли должна появится сумма чисел.

Затем перейдём в терминале в папку вашего проекта, а затем в папку где должен быть создан файл class. Это должно быть в папке out/production.

Для дизассемблирования запустите следующую команду, а в качестве параметра передайте скомпилированный класс:

Javap -c -p Main.class

С - дизассемблирование,
-p - вывод информации о всех членах класса.

В терминале мы должны получить следующее:

Public class org.dart.Main { public org.dart.Main(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return private static int adding(int, int); Code: 0: iload_0 1: iload_1 2: iadd 3: ireturn public static void main(java.lang.String); Code: 0: bipush 43 // литерал числа присвоенный первой переменной 2: istore_1 3: bipush 56 // литерал числа присвоенный второй переменной 5: istore_2 6: iload_1 7: iload_2 8: invokestatic #2 // Method adding:(II)I 11: istore_3 12: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 15: iload_3 16: invokevirtual #4 // Method java/io/PrintStream.println:(I)V 19: return }

Здесь можно увидеть много интересного, даже код который мы явно сами не писали. Например метод:

Public org.dart.Main(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return

Это не обычный метод, это конструктор. Он добавился автоматически при компиляции. Почему он добавляется это отдельная история.

Обратите внимание, кажется что нумерация строк кода внутри методов идёт не по порядку. Это не совсем так. Она учитывает длину параметров от которых зависят некоторые операции.

Рассмотрим метод складывающий два числа, с помощью комментариев поясним смысл операций:

Private static int adding(int, int); Code: 0: iload_0 // загрузка первого целого числа из параметра в стек 1: iload_1 // загрузка второго целого числа из параметра в стек 2: iadd // сложение двух чисел из стека и помещение результата в стек 3: ireturn // возвращение целого числа из метода

В данном случае все операции занимают строго по одному байту.
Со списком операций можно познакомится по этой ссылке:
список инструкций Java байткода

Из набора таких операции и их параметров состоит любая программа скомпилированная javac. В свою очередь JVM, при запуске программы, начинает интерпретировать команды, превращая некоторые блоки программы в машинный код с помощью JIT технологии.

Для эксперимента, можно посмотреть какой код получится для разных операций с разными типами данных. Так же можно проверить сколько байт будет отдаваться под данные для чисел превышающих один байт, то есть больших чем 255.

Может быть откомпилирован в байт-код Java, который затем может выполниться с помощью JVM.

JVM является ключевым компонентом платформы Java. Так как виртуальные машины Java доступны для многих аппаратных и программных платформ, Java может рассматриваться и как связующее программное обеспечение, и как самостоятельная платформа, отсюда принцип "написанное однажды, запускается везде" (write once, run anywhere). Использование одного байткода для многих платформ позволяет описать Java Как "скомпилированное однажды, запускается везде" (compile once, run anywhere).

Спецификация JVM

Противостояние Sun и IBM

В 2001 году, с целью разработки стандарта кросс-платформенных Desktop-приложений, Eclipse.

IBM VisualAge. IBM удалось сбалансировать интересы свободного сообщества и интересы бизнеса (свои интересы) в лицензии Eclipse Public License, признанной FSF .

Проект успешно развивается, признан индустрией, в значительной степени отделился от IBM в самостоятельную Eclipse Foundation .


Wikimedia Foundation . 2010 .

Смотреть что такое "Виртуальная машина Java" в других словарях:

    виртуальная машина Java - Основная часть исполняющей системы Java (Java Runtime Environment; JRE). Виртуальная машина Java интерпретирует и исполняет Java байт код, предварительно созданный из исходного текста Java программы Java компилятором. JVM может использоваться для … - разработан компанией JavaSoft. Web приложения, созданные с его использованием, могут выполняться естественным образом внутри операционной системы, или браузера Web, или внутри эмулирующей среды, известной как виртуальная машина Java … Словарь электронного бизнеса

    - (JPF) свободный инструмент для проверки многопоточных Java программ. По своей сути это виртуальная Java машина (англ. Java Virtual Machine) на основе которой реализованы методы проверки моделей (англ. model checking). Это означает, что… … Википедия

    виртуальная Java-машина - Интерпретатор байт кода Java программ. Виртуальная машина, предназначенная для исполнения Java аплетов. JVM встроена в большинство веб браузеров. Это позволяет исполнять на стороне клиента Java аплеты, вызовы которых предусмотрены в… … Справочник технического переводчика

    Иное название этого понятия «Ява»; см. также другие значения. Не следует путать с JavaScript. Java Класс языка … Википедия

    Необходимо проверить качество перевода и привести статью в соответствие со стилистическими правилами Википедии. Вы можете помочь улучшить эту статью, исправив в ней ошибки. Оригинал н … Википедия

Тут дали уже много хороших и правильных ответов, но хотелось бы уточнить, что вот эта метафора:

Виртуальня машина java это тоже интерпретатор по сути

может направить по весьма ложному пути!

У слов в названиях есть достаточно точный смысл, и JVM называется именно машиной , а не интерпретатором, и не компилятором совершенно не случайно. Компилятор в Яве есть (javac), и он нужен не для выполнения программы, а именно для ее компиляции (в байткод). Имено поэтому он не входит в состав JRE (среды выполнения), а содержится в JDK (среде разработки). В самой JVM есть еще один, JIT-компилятор, который компилирует байткод в инструкции процессора во время выполнения программы, но это уже другая история, и его тоже никак не назвать интерпретатором.

По сути JVM - это процессор, только виртуальный. И как у любого процессора (железного, типа x86, или виртуального, типа CLR в.NET), у него есть свой набор опкодов , называемый байткодом . Так же точно, как на х86 может выполняться код, порожденный компилятором с C++, или Pascal, или Go, так же и на JVM может выполняться байткод, скомпилированный из Java, или Scala, или Kotlin (или даже написанный вручную), а.class -файл, это, по сути, тот же.exe (точнее.so), скомпилированный под "процессор JVM". В этом и заключается кроссплатформенность. Так же, как код, скомпилированный под х86 будет выполняться на процессоре от Intel или AMD, так же и байткод JVM будет выполняться на JVM от Oracle, IBM, OpenJDK и т.д. И даже наличие JIT, компилирующего байткод в опкод конкретного железного процессора во время выполнения, все еще не дает повода обзывать честную стековую (SUN) или регистровую (Dalvik) VM интерпретатором, пусть даже и по сути:)

Дело в том, что сама эта классификация (интерпретируемый/компилируемый ЯЗЫК) последние лет эдак 25 уже практически лишена смысла. Языкам, изначально ориентированным на реализацию в виде интерпретатора (с просто анализируемой лексикой, чтоб интерпретатор был поменьше и мог оставить самой программе достаточно места в ограниченной по объему памяти) типа APL или BASIC, сейчас (кроме, разумеется, очень узкоспециального применения) почетное место разве что в старых учебниках, из которых эту самую классификацию, с достойным лучшего применения упорством, продолжают дословно переписывать в новые. При этом, почему-то, забывают уточнить, что эти два понятия уже давно не про сами языки, а всего лишь про некоторые методы их реализации, и что с тех пор помимо этих методов появилось еще много других хороших и разных концепций на эту тему (типа VM, JIT, сборщиков мусора, да и хотя бы тех же OOП, разных видов типизации и еще миллион чего), которых в тех учебниках еще просто не было в силу их года издания. И что на сегодня уже даже для языков, принципиально заточеных для компиляции под регистровую архитектуру, типа С, есть пруд пруди интерпретаторов (раз , два , три)... которые, опять же, никто не называет виртуальными машинами, т.к. это все суть разные понятия. Короче, это все равно что пытаться понять, где в квантовой механике огонь, вода, земля и воздух, в том виде, как их понимали Платон и Аристотель:)

P.S. Чтоб осознать, когда эта классификация еще была актуальна, рекомендую вот это . Там создатели APL, одного из первых настоящих интерпретируемых языков, обсуждают насущные проблемы языкостроения того времени. Если туго с английским, посмотрите хотя бы вступление... в тех железяках было меньше памяти и вычислительной мощности, чем в современной симке:)

JVM (Виртуальная Машина Java) - основа языка программирования Java. Среда Java состоит из пяти элементов:
Язык Java
■ Определение байт-кода
■ Библиотеки класса Java/Sun
■ Виртуальная машина Java
■ Структура файла.class

Из всех этих пяти элементов, элементы, которые привели к успеху Java
■ Определение байт-кода,
■ структура файла.class,
■ и Виртуальная машина Java.

Таким образом "write once and run anywhere", было фактически осуществлено благодаря мобильности файла.class, который помогает выполнению на любом компьютере или наборе микросхем с использованием Виртуальной Машины Java.

1.3.1 Что такое Виртуальная машина Java?

Виртуальная машина - это программное обеспечение, основанное на понятиях и идее относительно воображаемого компьютера, который имеет логический набор команд, и команд, определяющих операции этого компьютера. Это.можно сказать, небольшая операционная система. Она формирует необходимый уровень абстракции, где достигается независимость от платформы, используемого оборудования.

Компилятор конвертирует исходный текст в код, который основан на воображаемой системе команд компьютеров и не зависит от специфичности процессора. Интерпретатор -приложение, которое понимает эти потоки команд и преобразовывает эти команды для используемого оборудования, к которому относится интерпретатор. JVM создает систему поддержки выполнения внутренне, что помогает выполнению кода при
■ загрузке файлов.class,
■ управлению памятью
■ выполнении обработки исключений.

Из-за несогласованности аппаратных платформ виртуальная машина использует понятие стека, который содержит следующую информацию:
■ Описатели состояния метода
■ Операнды к байт-кодам
■ Параметры методов
■ Локальные переменные

Когда код выполняется с помощью JVM, то существует один специальный регистр, который используется как счетчик, указывая выполняющиеся в настоящее время команды. Если необходимо, команды изменяют программу, изменяют поток выполнения, иначе поток последователен и переходит от одной команды к другой.

Другое понятие, которое становится популярным - это использование Just In Time (JIT) компилятора. Браузеры подобно Netscape Navigator 4.0 и Internet Explorer 4.0 включают JIT компиляторы, которые увеличивают скорость выполнения кодов Java. Основная цель JIТ состоит в том, чтобы преобразовать систему команд байт-кода к машинным командам кода, целенаправленным для специфического микропроцессора. Эти команды сохраняются и используются всякий раз, когда запрос делается к этому специфическому методу.

1.3.2 Среда выполнения Java

JRE (Java Runtime Environment, среда выполнения Java) JVM взаимодействующего с аппаратными средствами на одной стороне и программе на другом. JRE выполняет код, откомпилированный для JVM:
Загрузка.class файлов
Выполняется с помощью "Загрузчика классов"
Загрузчик класса делает проверку защиты, если файлы используются в сети.
Проверка байт-кода
Выполняется "верификатором байт-кода"
Верификатор байт-кода проверяет формат кода, преобразования типов объектов и проверяет нарушение прав доступа.
Выполнение кода
Выполняется "интерпретатором во время выполнения"
Интерпретатор выполняет байт-коды и делает запросы на используемое оборудование.


Рисунок 1.3: Среда выполнения Java

1.3.3 Обработка исключений и управление памятью

В С, C++ или Паскале, программисты использовали примитивные методы распределения и освобождения блоков памяти - динамическую память. Динамическая память -большой кусок памяти, который обозначен в объёме всей памяти.

Динамическая память используется:
Свободный блочный список
Распределённый блочный список

Свободный список проверяет блок памяти всякий раз, когда делается запрос. Используется механизм распределения - "метод первого подходящего блока", посредством чего первый наименьший блок памяти распределяется в зависимости от запроса. Эта процедура распределяет и освобождает небольшие объёмы памяти различных размеров от динамической памяти, при этом фрагментация динамической памяти сводится к минимуму.

Существует стадия, посредством которой выполняется запрос к памяти - для получения большего блока памяти, чем доступно. В таких случаях программа управления динамической областью должна создать больше памяти. Эту методику называют уплотнением. Это процесс, посредством которого все свободные доступные блоки памяти объединяются вместе, перемещая свободную память одному из концов динамической памяти, таким образом создавая один большой блок памяти.

Виртуальная Машина Java использует две отдельные динамических памяти для статического и динамического распределения памяти.

Динамическая память - не делает обработку исключений динамической памяти, которая сохраняет все свойства класса, постоянный пул и таблицы методов.

Вторая динамическая память снова разделена на два раздела, которые могут быть расширены в противоположных направлениях когда потребуется. Один раздел используется, чтобы сохранять образцы объектов, а другой раздел используется, чтобы сохранять дескрипторы в эти образцы. Дескриптор - структура, которая состоит из двух указателей. Указываете на таблицу методов объекта и других пунктов к образцу того объекта. Это размещение в основном устраняет потребность сохранения путей, указывающих на объект при модифицировании указателей после уплотнения. Все, что мы должны сделать - это обновить значение указателя дескриптора.

Алгоритм обработки исключений применяется к объектам, помещенным в динамическую память. Поскольку запрос о блоке памяти получен, программа управления динамической областью первые проверки свободный список и если программа управления динамической областью не может найти свободные блоки памяти, вызывается обработка исключений, как только система имеет простой в течение достаточного периода времени. В случаях, когда приложения очень интерактивны и время простоя системы сведено к минимуму, обработку исключений нужно вызвать явно приложением.

Коллектор исключений вызывает завершающийся метод прежде, чем с помощью обработки исключений собирается образец объекта. Завершающийся метод используется чтобы очистить внешние ресурсы подобно файлам и потокам, которые являются открытыми и о которых не позаботились в стандартной обработке исключений. Даже если мы явно вызываем обработку исключений методом (System.gc ()), это не будет работать быстро. Это просто намечено для того, чтобы работать. Также это означает, что обработка исключений не может быть вызвана. Это объясняется тем, что потоки обработки исключений выполняются в очень низком приоритете и могут часто прерываться. Это может случиться, когда наш объект никогда не располагался ранее в памяти.







2024 © gtavrl.ru.