Кроссплатформенность - «написано/скомпилировано однажды, запускается везде» (compile once, run anywhere).
Приложения Java обычно транслируются в специальный байт-код, поэтому они могут работать на любой компьютерной архитектуре, для которой существует реализация виртуальной Java- машины.
Байт-код Java - набор инструкций, исполняемых виртуальной машиной Java.
Каждый код операции байт-кода - один байт. Используются не все 256 возможных значений кодов операций.
51 из них зарезервированы для использования в будущем.
Java Virtual Machine (JVM) - виртуальная машина Java - основная часть исполняющей системы Java, так называемой Java Runtime Environment (JRE).
Виртуальная машина Java исполняет байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java (javac). JVM может также использоваться для выполнения программ, написанных на других языках программирования.
Например, исходный код на языке Ada может быть скомпилирован в байт-код Java, который затем может выполниться с помощью JVM.
Специфическая для Java методология распределенных вычислений называется Remote Method Invocation (RMI). RMI позволяет использовать все преимущества Java: безопасность, независимость от платформы и объектно-ориентированное программирование для распределенных вычислений.
Java Development Kit (JDK) - комплект разработчика приложений на языке Java:
JDK позволяет разработчикам создавать программы, которые могут выполняться и запускаться посредством JVM и JRE;
Java Runtime Environment (JRE среда выполнения для Java) - минимальная реализация виртуальной машины, необходимая для исполнения Java-приложений, без компилятора и других средств разработки: Java Virtual Machine + и библиотеки Java-классов.
Виртуальная машина Java — программное обеспечение, отвечающее за выполнение Java-программ. JRE — это программа, которая берет ваш Java-код, объединяет его с необходимыми библиотеками и запускает JVM для его выполнения. JRE содержит программное обеспечение и библиотеки, которые требуются для работы вашей программы. Например, загрузчик классов JAVA является частью JRE. Эта важная часть программного обеспечения загружает скомпилированный Java-код в память и соединяет с соответствующими библиотеками. В этом многоуровневом представлении JVM создается средой выполнения Java. С точки зрения пакета, JRE содержит JVM, как показано на рисунке:
Java Virtual Machine (JVM) - это программа, предназначенная для выполнения других программ.
Это основная часть JRE. Исполняет байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java (javac). JVM может также использоваться для выполнения программ, написанных на других языках программирования.
Например, исходный код на языке Ada может быть скомпилирован в байт-код Java, который затем может выполниться с помощью JVM
JVM имеет две основные функции:
Промежуточное представление кода, в которое может быть переведена компьютерная программа автоматическими средствами. Машинно-независимый код низкого уровня, генерируемый транслятором из исходного кода - набор валидных (соответствующих спецификации Java) команд.
Загрузчик классов является частью JRE, которая динамически загружает Java классы в JVM.
Обычно классы загружаются только по запросу. Система исполнения в JAVA не должна знать о файлах и файловых системах благодаря загрузчику классов. Делегирование является важной концепцией, которую выполняет загрузчик.
Загрузчик классов отвечает за поиск библиотек, чтение их содержимого и загрузку классов, содержащихся в библиотеках. Эта загрузка обычно выполняется «по требованию», поскольку она не происходит до тех пор, пока программа не вызовет класс. Класс с именем может быть загружен только один раз данным загрузчиком классов.
При запуске JVM, используются три загрузчика классов:
Загрузчик класса Bootstrap - загружает основные библиотеки Java, расположенные в папке <JAVA_HOME>/jre/lib. Этот загрузчик является частью ядра JVM, написан на нативном коде.
Загрузчик класса расширений - загружает код в каталоги расширений. <JAVA_HOME>/jre/lib/ext, или любой другой каталог, указанный системным свойством java.ext.dirs.
Системный загрузчик - загружает код, найденный в JAVA.class.path, который сопоставляется с
переменной среды CLASSPATH. Это реализуется классом sun.misc
Загрузчик классов выполняет три основных действия в строгом порядке:
Загрузчик классов написан на Java. Поэтому возможно создать свой собственный загрузчик классов, не понимая тонких деталей JVM. У каждого загрузчика классов JAVA есть родительский загрузчик классов, определенный при создании экземпляра нового загрузчика классов или в качестве системного загрузчика классов по умолчанию для виртуальной машины.
Что делает возможным следующее:
Например, это одна из основ протоколов CORBA / RMI;
(например, можно использовать зашифрованный байт-код класса Java);
(например, для переплетения аспектов во время загрузки при использовании аспектно-ориентированного программирования);
JIT-компиляция (англ. Just-in-time compilation, компиляция «на лету»), динамическая компиляция (англ. dynamic translation) - технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы.
Способ автоматического управления памятью.
Сборщик мусора (Garbage Collector) должен делать всего две вещи:
Объект считается неиспользуемым, если ни одна из сущностей в коде, выполняемом в данный момент, не содержит ссылок на него, либо цепочка ссылок, которая могла бы связать объект с некоторой сущностью приложения, обрывается.
Работа сборщика мусора не бесплатная, она оплачивается ресурсами компьютера и задержками в выполнении программы.
Существует два подхода к обнаружению мусора:
Reference counting (подсчёт ссылок).
Суть этого подхода состоит в том, что каждый объект имеет счетчик. Счетчик хранит информацию о том, сколько ссылок указывает на объект. Когда ссылка уничтожается, счетчик уменьшается. Если значение счетчика равно нулю - объект можно считать мусором.
Главным минусом такого подхода является сложность обеспечения точности счетчика. Также при таком подходе сложно выявлять циклические зависимости (когда два объекта указывают друг на друга, но ни один живой объект на них не ссылается), что приводит к утечкам памяти.
Tracing (трассировка)
- живыми могут считаться только те объекты, до которых мы можем добраться из корневых точек (GC Root) и те объекты, которые доступны с живого объекта. Всё остальное - мусор.
Существует 4 типа корневых точки:
Самое простое java приложение будет иметь корневые точки:
Таким образом, если мы представим все объекты и ссылки между ними как дерево, то нам нужно будет пройти с корневых узлов (точек) по всем рёбрам. При этом узлы, до которых мы сможем добраться - не мусор, все остальные - мусор. При таком подходе циклические зависимости легко выявляются. HotSpot VM использует именно такой подход.
Для очистки памяти от мусора существуют два основных метода:
При Copying collectors подходе память делится на две части «from-space» и «to-space», при этом сам принцип работы такой:
Главный плюс такого подхода в том, что объекты плотно забивают память.
Минусы подхода:
Алгоритм работы mark-and-sweep можно описать так:
Минусы этого способа:
Они используют комбинированный подход Generational Garbage Collection , который позволяет использовать разные алгоритмы для разных этапов сборки мусора.
Этот подход опирается на том, что:
Механизм сборки мусора - это процесс освобождения места в куче, для возможности добавления новых объектов.
Объекты создаются посредством оператора new , тем самым присваивая объекту ссылку.
Для окончания работы с объектом достаточно просто перестать на него ссылаться, например, присвоив переменной ссылку на другой объект или значение null. Так же можно прекратить выполнение метода, чтобы его локальные переменные завершили свое существование естественным образом.
Объекты, на которые отсутствуют ссылки, принято называть мусором (garbage), который будет удален.
Виртуальная машина Java, применяя механизм сборки мусора, гарантирует, что любой объект, обладающий ссылками, остается в памяти — все объекты, которые недостижимы из исполняемого кода, ввиду отсутствия ссылок на них, удаляются с высвобождением отведенной для них памяти. Точнее говоря, объект не попадает в сферу действия процесса сборки мусора, если он достижим посредством цепочки ссылок, начиная с корневой (GC Root) ссылки, т.е. ссылки, непосредственно существующей в выполняемом коде.
Память освобождается сборщиком мусора по его собственному «усмотрению». Программа может успешно завершить работу, не исчерпав ресурсов свободной памяти или даже не приблизившись к этой черте и поэтому ей так и не потребуются «услуги» сборщика мусора.
Мусор собирается системой автоматически, без вмешательства пользователя или программиста, но это не значит, что этот процесс не требует внимания вовсе. Необходимость создания и удаления большого количества объектов существенным образом сказывается на производительности приложений и если быстродействие программы является важным фактором, следует тщательно обдумывать решения, связанные с созданием объектов, — это, в свою очередь, уменьшит и объем мусора, подлежащего утилизации.
Java HotSpot VM предоставляет разработчикам на выбор четыре различных сборщика мусора:
Serial (последовательный) — самый простой вариант для приложений с небольшим объемом данных и не требовательных к задержкам. На данный момент используется сравнительно редко, но на слабых компьютерах может быть выбран виртуальной машиной в качестве сборщика по умолчанию.
Использование Serial GC включается опцией:
Parallel (параллельный) — наследует подходы к сборке от последовательного сборщика, но добавляет параллелизм в некоторые операции, а также возможности по автоматической подстройке под требуемые параметры производительности.
Параллельный сборщик включается опцией:
Concurrent Mark Sweep (CMS) — нацелен на снижение максимальных задержек путем выполнения части работ по сборке мусора параллельно с основными потоками приложения. Подходит для работы с относительно большими объемами данных в памяти.
Использование CMS GC включается опцией:
Garbage-First (G1) — создан для замены CMS, особенно в серверных приложениях, работающих на многопроцессорных серверах и оперирующих большими объемами данных.
G1 включается опцией Java:
Heap (куча) используется Java Runtime для выделения памяти под объекты и классы.
Создание нового объекта также происходит в куче. Это же является областью работы сборщика мусора. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться из любой части приложения.
Stack (стек) это область хранения данных также находящееся в общей оперативной памяти (RAM) только для одного потока.
Всякий раз, когда вызывается метод, в памяти стека создается новый блок, который содержит примитивы и ссылки на другие объекты в методе. Как только метод заканчивает работу, блок также перестает использоваться, тем самым предоставляя доступ для следующего метода. Размер стековой памяти намного меньше объема памяти в куче. Стек в JAVA работает по схеме LIFO (Последний-зашел-Первый-вышел)
ИсточникЕсли память стека полностью занята, то Java Runtime бросает исключение:
java.lang.StackOverflowError
Если заполнена память кучи, то бросается исключение:
java.lang.OutOfMemoryError: Java Heap Space
Не совсем. Примитивное поле экземпляра класса хранится не в стеке, а в куче. Любой объект (всё, что явно или неявно создаётся при помощи оператора new) хранится в куче.
в JAVA параметры всегда передаются только по значению, что определяется как «скопировать значение и передать копию». С примитивами это будет копия содержимого. Со ссылками - тоже копия содержимого, т.е. копия ссылки. При этом внутренние члены ссылочных типов через такую копию изменить возможно, а вот саму ссылку, указывающую на экземпляр - нет.