Try English version of Quizful



Раздаем бесплатные Q! подробности в группе Quizful.Alpha-test
Партнеры
Рекрутерам: Прескрининг кандидатов about
Топ контрибуторов
loading
loading
Знаете ли Вы, что

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

Лента обновлений
ссылка 20:57:36
Комментарий от Recrut_rf:
Спасибо, сохранил функцию, может пригодится когда - ни...
ссылка 20:53:59
Добавлен вопрос в тест ASP.NET - Основы
ссылка 08:41:09
Комментарий от Krosster:
Гарний сайт для новачків. Правда деякі питання підступн...
ссылка Apr 22 22:06
Добавлен вопрос в тест SQL - Средний уровень
ссылка Apr 22 10:13
Комментарий от Entrery:
вроде выбрал ООП в сишарпе, а тут вопросы по джаве...
Статистика

Тестов: 153, вопросов: 8596. Пройдено: 402470 / 1961091.

Классификация и функции загрузчиков классов

head tail Статья
категория
Java
дата31.05.2013
авторvovanok
голосов75

Введение

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

    Все классы в Java загружаются с помощью загрузчиков классов.  Вначале работы программы создается 3 основных загрузчика классов:

  1. базовый загрузчик (bootstrap)
  2. загрузчик расширений (extention)
  3. системный загрузчик (system/application)

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

Загрузчики классов являются иерархическими. Загрузчик, который загружает основные системные классы, называется базовым (Bootstrap или Primordial) загрузчиком классов. Именно он загружает внутренние классы JDK  и пакеты java.* (rt.jar и i18n.jar) . Важно заметить, что базовый загрузчик является «Изначальным или Корневым» и частью JVM, вследствие чего его нельзя создать внутри кода программы.

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

Итак,  загрузчик расширений – загружает различные пакеты расширений, которые располагаются в директории <JAVA_HOME>/lib/ext или другой директории, описанной в системном параметре java.ext.dirs. Это позволяет обновлять и добавлять новые расширения без необходимости модифицировать настройки используемых приложений. Загрузчик расширений реализован классом sun.misc.Launcher$ExtClassLoader. 

И, наконец, системный загрузчик – загружает классы, пути к которым указаны в переменной окружения CLASSPATH или пути, которые указаны в командном рядке после ключей  –classpath или  –cp. Системный загрузчик реализован классом sun.misc.Launcher$AppClassLoader.  

 

Принцип работы загрузчиков классов

    Каждый загрузчик классов (кроме Bootstrap) имеет родительский загрузчик, и в большинстве случаев он запрашивает родительского загрузчика загрузить указанный класс, перед тем как попробовать загрузить его самостоятельно. 

    Существует так же явный  способ инициировать загрузку требуемого класса. Явное инициирование выполняться с помощью методов ClassLoader.loadClass() или Class.forName(). Например явное инициирование используется при загрузке JDBC драйверов: Class.forName("oracle.jdbc.driver.OracleDriver");

Иерархия загрузчиков классов выглядит следующим образом:

1 Bootstrap
2 Extensions
3 Application
4 Пользовательский (если существует)

Что бы получить загрузчик класса в коде, нужно воспользоваться методом getClassLoader(), например:

public class ClassLoadersTest {

    public static void main(String[] args){

        Integer i = 23;

        System.out.println(i.getClass().getClassLoader());

    }

}

   

    Вызов i.getClass().getClassLoader() вернет null, что свидетельствует о том, что класс был загружен именно базовым загрузчиком.

    Давайте рассмотрим процесс загрузки классов более детально. Допустим, у нас есть некий класс, который мы будем загружать (например Integer). Процесс загрузки будет следующим:

  1. Cистемный загрузчик (sun.misc.Launcher$AppClassLoader) проверит, не загружался ли данный класс ранее. Если он уже загружался, то возвращается данный класс из кэша. Если нет,  системный загрузчик делегирует поиск класса родительскому классу-загрузчику.
  2. Загрузчик расширений (sun.misc.Launcher$ExtClassLoader) выполняет такую же процедуру
  3. Наконец, базовый загрузчик(bootstrap), загружает класс Integer самостоятельно, поскольку у него нет родительского класса.

    Таким образом, процесс загрузки имеет одно важное свойство, а именно делегирование (рисунок 1). Это позволяет загружать классы тем загрузчиком, который находится ближе всего к базовому в иерархии делегирования. Как следствие поиск классов будет происходить в источниках в порядке их доверия: сначала в библиотеке core API,  потом в папке расширений, потом в локальных файлах classpath.

Иерархия

 

    Другими словами, если бы вы скачали стороннюю библиотеку с классом Integer и указали ее в переменной пути, то загрузился бы все равно оригинальный Integer(целое число).

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

 

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

    В Java существует возможность создания собственных загрузчиков классов. Это может быть полезно, когда нет возможности или нежелательно перечислять все используемые библиотеки при старте программы в CLASSPATH. Например, в программе должна быть возможность динамической загрузки плагинов. Или возможностей стандартного загрузчика недостаточно для загрузки нужных классов.

    Собственные загрузчики классов используют все серверы приложений и web-контейнеры, что и понятно – приложения, разворачиваемые на сервере приложений, должны загружаться динамически, в противном случае перечисление в переменной CLASSPATH всех библиотек, используемых приложениями, становится задачей нетривиальной.

    За создание пользовательских загрузчиков классов отвечает класс  ClassLoader. Для того, что бы создать собственный загрузчик классов, необходимо унаследоваться от класса ClassLoader .

   Процесс создания собственного загрузчика хорошо описан в статье: http://samolisov.blogspot.com/2008/01/java.html

 

Процесс загрузки класса более детально

Процесс загрузки класса состоит из трех частей:

1.     Loading

2.     Linking

3.     Initialization


clphases

 

    Loading – на этой фазе происходит поиск и физическая загрузка файла класса в определенном источнике (в зависимости от загрузчика). Этот процесс определяет базовое представление класса в памяти. На этом этапе такие понятия как методы, поля и т.д. пока не известны.

    Linking – процесс, который может быть разбит на 3 части:

  1. Bytecode verification – происходит несколько проверок байт-кода  на соответствие ряду зачастую нетривиальных требований определенных в спецификации JVM (http://java.sun.com/docs/books/vmspec/).
  2. Class preparation – на этом этапе происходит подготовки структуры данных, отображающей поля, методы и реализованные интерфейсы, которые определены в классе.
  3. Resolving – разрешение все классов, которые ссылаются на текущий класс.

    Initialization – происходит выполнение статических инициализаторов определенных в классе. Таким образом, статические поля инициализируются стандартными значениями.

    Детально о фазах загрузки: http://www.artima.com/insidejvm/ed2/lifetype.html

 

Исключения

При работе загрузчиков классов наиболее часто встречаются следующие исключительные ситуации:

1.  ClassNotFoundException, бросается, когда приложение пытается загрузиться класс  по его названию (String) с помощью таких средств:

  • forName метод в классе Class.
  • findSystemClass метод в классе ClassLoader.
  • loadClass метод в классе ClassLoader.

Но класса с таким именем  не существует.

2.  NoClassDefFoundError, бросается в таких случаях:

  • Когда архив, директория, или другой источник необходимых классов не был добавлен в источники текущего загрузчика классов или его предка.
  • Загрузчик-предок не был установлен корректно.

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


Выгрузка классов

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

    Загруженные классы, несмотря на то, что являются полноценными Java-объектами, хранятся в особой системной области памяти, называемой permament generation (сокращенно, PermGen) и управляемой сборщиком мусора.

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

Конкретная политика выгрузки классов во многом зависит от реализации виртуальной машины JVM.

 

Заключение

    Таким образом, мы с вами немного приблизились к пониманию процесса загрузки классов в JVM. Были рассмотрены типы загрузчиков, их иерархия, фазы загрузки класса и исключительные ситуации, которые могут возникнуть в процессе.

Если Вам понравилась статья, проголосуйте за нее

Голосов: 75  loading...
AlexVovolka   Diab1o   kabdev   nagibator000   Glare   GalaranF   fdk512   AngryCellophane   alex81   sergeystets   Xelen   pma09   kyryll19   andrey_z91h   Anatoly_Burov   olsan   epateev   mate   a_k_alehin   lula   dezmond   ELetenkov   scspy   moreking   Letos   lano4ka   stp008   fdman   tenka   McKey92   TeaWitch   Amagister   Tomkevich   dimaz1992   AckiyBolt   Pasha_Pasha   rshark14   andrik92   pristroistvo_ek   squareroot   DanikG   rorybreaker   SamTan   GesValery   mabden   superlogin   E_Nigmo   LenaHolkina   grantemon   tarasenkoo   DmitryOrlik   Wonderkot   Lulu05   tamcha   ziplee   ilja_chitneev   WinFakt   Legendary   Hanni   StateItPrimitiv   Philiow   Alexis220382   rapackivi   ffw_ATL   JustPepsi   joinhud   alesandrus   arxemond   strexet   Str1kerTT   stasyan72   Dimagious   lelik112   amaksim   ir_kam