JAVA Base

Вопросы к собеседованию

Вопросы:

Какая основная идея языка?

Кроссплатформенность - «написано/скомпилировано однажды, запускается везде» (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.

EBC

Какие преимущества у JAVA?

Какие недостатки у JAVA?

Что такое JDK? Что в него входит?

Java Development Kit (JDK) - комплект разработчика приложений на языке Java:

JDK позволяет разработчикам создавать программы, которые могут выполняться и запускаться посредством JVM и JRE;

JDK
Источник

Что такое JRE? Что в него входит?

Java Runtime Environment (JRE среда выполнения для Java) - минимальная реализация виртуальной машины, необходимая для исполнения Java-приложений, без компилятора и других средств разработки: Java Virtual Machine + и библиотеки Java-классов.

Как JRE работает с JVM

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

JRE
Подробнее

Что такое JVM?

Java Virtual Machine (JVM) - это программа, предназначенная для выполнения других программ.

Это основная часть JRE. Исполняет байт-код Java, предварительно созданный из исходного текста Java-программы компилятором Java (javac). JVM может также использоваться для выполнения программ, написанных на других языках программирования.

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

JVM имеет две основные функции:

  1. Позволяет запускать Java-приложения на любых устройствах или операционных системах.
  2. Управляет и оптимизирует память, используемую приложением.
Подробнее

Что такое byte code?

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

Что такое загрузчик классов (classloader)?

Загрузчик классов является частью 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.Launcher$AppClassLoader.

Загрузчик классов выполняет три основных действия в строгом порядке:

Пользовательский загрузчик классов

Загрузчик классов написан на Java. Поэтому возможно создать свой собственный загрузчик классов, не понимая тонких деталей JVM. У каждого загрузчика классов Java есть родительский загрузчик классов, определенный при создании экземпляра нового загрузчика классов или в качестве системного загрузчика классов по умолчанию для виртуальной машины.

Что делает возможным следующее:

Что такое JIT?

JIT-компиляция (англ. Just-in-time compilation, компиляция «на лету»), динамическая компиляция (англ. dynamic translation) - технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы.

Что такое сборщик мусора?

Способ автоматического управления памятью.

Сборщик мусора (Garbage Collector) должен делать всего две вещи:

Работа сборщика мусора не бесплатная, она оплачивается ресурсами компьютера и задержками в выполнении программы.


Обнаружение мусора

Существует два подхода к обнаружению мусора:

Reference counting (подсчёт ссылок).

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

Главным минусом такого подхода является сложность обеспечения точности счетчика. Также при таком подходе сложно выявлять циклические зависимости (когда два объекта указывают друг на друга, но ни один живой объект на них не ссылается), что приводит к утечкам памяти.

Tracing (трассировка)

- живыми могут считаться только те объекты, до которых мы можем добраться из корневых точек (GC Root) и те объекты, которые доступны с живого объекта. Всё остальное - мусор.

Существует 4 типа корневых точки:

  • Локальные переменные и параметры методов;
  • Потоки;
  • Статические переменные;
  • Ссылки из JNI.

Самое простое java приложение будет иметь корневые точки:

  • Локальные переменные внутри main() метода и параметры main() метода;
  • Поток который выполняет main();
  • Статические переменные класса, внутри которого находится main() метод.

Таким образом, если мы представим все объекты и ссылки между ними как дерево, то нам нужно будет пройти с корневых узлов (точек) по всем рёбрам. При этом узлы, до которых мы сможем добраться - не мусор, все остальные - мусор. При таком подходе циклические зависимости легко выявляются. HotSpot VM использует именно такой подход.


Очистка от мусора

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

При Copying collectors подходе память делится на две части «from-space» и «to-space», при этом сам принцип работы такой:

Главный плюс такого подхода в том, что объекты плотно забивают память.

Минусы подхода:

  1. Приложение должно быть остановлено на время, необходимое для полного прохождения цикла сборки мусора;
  2. В худшем случае (когда все объекты живые) «form-space» и «to-space» будут обязаны быть одинакового размера.

Алгоритм работы mark-and-sweep можно описать так:

Минусы этого способа:

  1. Приложение не работает пока происходит сборка мусора;
  2. Время остановки напрямую зависит от размеров памяти и количества объектов;
  3. Если не использовать «compacting» память будет использоваться не эффективно.

Сборщики мусора HotSpot VM

Они используют комбинированный подход Generational Garbage Collection , который позволяет использовать разные алгоритмы для разных этапов сборки мусора.

Этот подход опирается на том, что:


Как работает сборщик мусора?

Механизм сборки мусора - это процесс освобождения места в куче, для возможности добавления новых объектов.

Объекты создаются посредством оператора new , тем самым присваивая объекту ссылку.

Для окончания работы с объектом достаточно просто перестать на него ссылаться, например, присвоив переменной ссылку на другой объект или значение null. Так же можно прекратить выполнение метода, чтобы его локальные переменные завершили свое существование естественным образом.

Объекты, на которые отсутствуют ссылки, принято называть мусором (garbage), который будет удален.

Виртуальная машина Java, применяя механизм сборки мусора, гарантирует, что любой объект, обладающий ссылками, остается в памяти — все объекты, которые недостижимы из исполняемого кода, ввиду отсутствия ссылок на них, удаляются с высвобождением отведенной для них памяти. Точнее говоря, объект не попадает в сферу действия процесса сборки мусора, если он достижим посредством цепочки ссылок, начиная с корневой (GC Root) ссылки, т.е. ссылки, непосредственно существующей в выполняемом коде.

Память освобождается сборщиком мусора по его собственному «усмотрению». Программа может успешно завершить работу, не исчерпав ресурсов свободной памяти или даже не приблизившись к этой черте и поэтому ей так и не потребуются «услуги» сборщика мусора.

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


Какие разновидности сборщиков мусора реализованы в виртуальной машине HotSpot?

Java HotSpot VM предоставляет разработчикам на выбор четыре различных сборщика мусора:

Что такое Heap и Stack память в Java?

Heap (куча) используется Java Runtime для выделения памяти под объекты и классы.

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

Stack (стек) это область хранения данных также находящееся в общей оперативной памяти (RAM) только для одного потока.

Всякий раз, когда вызывается метод, в памяти стека создается новый блок, который содержит примитивы и ссылки на другие объекты в методе. Как только метод заканчивает работу, блок также перестает использоваться, тем самым предоставляя доступ для следующего метода. Размер стековой памяти намного меньше объема памяти в куче. Стек в Java работает по схеме LIFO (Последний-зашел-Первый-вышел)

Источник


Различия между Heap и Stack

Для определения начального и максимального размера памяти в куче используются -Xms и -Xmx опции JVM. Для стека определить размер памяти можно с помощью опции -Xss. Размер стека задаётся при создании потока, и у каждой переменной есть максимальный размер, зависящий от типа данных, размер кучи ограничен оперативной памятью.

Верно ли утверждение, что примитивные типы данных всегда хранятся в стеке, а экземпляры ссылочных типов данных в куче?

Не совсем. Примитивное поле экземпляра класса хранится не в стеке, а в куче. Любой объект (всё, что явно или неявно создаётся при помощи оператора new) хранится в куче.


Каким образом передаются переменные в методы, по значению или по ссылке?

В Java параметры всегда передаются только по значению, что определяется как «скопировать значение и передать копию». С примитивами это будет копия содержимого. Со ссылками - тоже копия содержимого, т.е. копия ссылки. При этом внутренние члены ссылочных типов через такую копию изменить возможно, а вот саму ссылку, указывающую на экземпляр - нет.