Механизм загрузки класса JVM от входа в JVM

JVM

предисловие

Текст был включен в мой репозиторий GitHub, добро пожаловать, звезда:GitHub.com/bin39232820…
Лучшее время посадить дерево было десять лет назад, затем сейчас

болтовня

Любой, кто изучает Java, не может избежать виртуальной машины Java, поэтому эта серия является обязательной, потому что, если вы хотите построить свою систему знаний Java, вы должны знать, как изучать ее шаг за шагом. JVM Давайте составим небольшой план, начиная с введения JVM, затем файл Java программируется в файл .class, а затем как виртуальная машина Java загружает файл .class, и после загрузки его в виртуальную машину, как хранить эти данные в виртуальной машине Java, мы знаем после хранения.Java автоматически собирает мусор, в отличие от C C++, затем мы должны знать алгоритм сборки мусора, сборщик мусора и, наконец, настройку JVM реальной системы Java.Это это серия, о которой я планирую рассказать, а затем большинство моих занятий посвящено глубокому пониманию виртуальной машины Java г-ном Чжоу Чжимином.

что такое JVM

JVM — это аббревиатура от Java Virtual Machine (Виртуальная машина Java).JVM — это спецификация для вычислительных устройств.Это вымышленный компьютер, реализованный путем имитации различных компьютерных функций на реальном компьютере. Виртуальная машина Java включает в себя набор инструкций байт-кода, набор регистров, стек, кучу для сборки мусора и поле метода хранения. JVM скрывает информацию, относящуюся к конкретной платформе операционной системы, так что программе Java нужно только генерировать объектный код (байтовый код), работающий на виртуальной машине Java, и она может работать на различных платформах без изменений. Когда JVM выполняет байт-код, она фактически интерпретирует байт-код в машинные инструкции на конкретной платформе для выполнения, что является причиной того, что Java является кросс-платформенной.

JDK JRE JVM

Это снимок экрана, который я взял с официального сайта oracle, из которого видно, что JDK=JRE+некоторые инструменты, JRE содержит JVM (виртуальную машину Java)

Общий обзор JVM

JVM обычно состоит из

  • Подсистема загрузчика классов (ClassLoader)
  • область данных времени выполнения
  • исполнительный механизм
  • восстановление памяти
  • структура файла класса

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

Что такое механизм загрузки классов

Оригинальные слова из книги:

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

время загрузки класса

Класс начинается с загрузки в память виртуальной машины и заканчивается выгрузкой из памяти, его жизненный цикл включает

  • нагрузка
  • проверять
  • Подготовить
  • Разобрать
  • инициализация
  • использовать
  • удалить

Всего 7 этапов

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

Прежде всего, класс относится к классу файла .Class, так как же сгенерировать этот файл?

  • Компиляция Java-кода
  • Первоначально файл .Class
  • Генерация динамического прокси

подождите, есть еще много

Итак, как вы должны понимать два слова загрузки?Вы можете увидеть картинку ниже

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

  1. Получить двоичный поток байтов, определяющий класс по его полному имени
  2. Преобразуйте статическую структуру хранения, представленную этим потоком байтов, в двоичный поток байтов в области метода.
  3. Объект Java.lang.Class этого класса генерируется в области методов памяти как запись для каждого доступа к данным этого класса.

Пять ситуаций, которые необходимо инициализировать

Java не определяет первый этап загрузки класса во время жизни, но для этапа инициализации виртуальная машина имеет строгие спецификации.

  • При встрече с новым ключевым словом
  • При использовании метода пакета Reflect
  • При инициализации класса обнаруживается, что родительский класс не был инициализирован, и родительский класс должен быть инициализирован первым
  • Когда виртуальная машина запустится, загрузите класс основного метода
  • При использовании динамической языковой поддержки 1.7 (эту штуку я не трогал, кто-нибудь ее понимает)

этап проверки

Делится на следующие образцы

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

Этап подготовки

Фаза подготовки — это фаза, на которой формально выделяется память для переменных класса и устанавливаются начальные значения переменных класса, все из которых будут выделены в области методов. На этом этапе есть несколько замечаний:

1. В настоящее время выделение памяти включает только переменные класса (статические), а не переменные экземпляра.Переменные экземпляра будут выделены в куче Java вместе с объектом при создании экземпляра объекта.

2. Установленное здесь начальное значение обычно является нулевым значением по умолчанию для типа данных (например, 0, 0L, null, false и т. д.), а не значением, явно назначенным в коде Java.

Предположим, что переменная класса определена как:

общедоступное статическое целочисленное значение = 3;

Тогда начальное значение переменной value после этапа подготовки равно 0, а не 3, потому что ни один Java-метод еще не выполнялся, а инструкция putstatic, присваивающая значение 3, сохраняется в методе конструктора класса() после компиляции программы Среди них действие присвоения значения 3 не будет выполняться до фазы инициализации.

В следующей таблице перечислены все основные типы данных в Java и нулевое значение по умолчанию для ссылочных типов:

Вот еще несколько замечаний:

  • Для базовых типов данных, для переменных класса (статических) и глобальных переменных, если они используются напрямую без их явного присвоения, система присвоит им значение по умолчанию, равное нулю, а - для локальных переменных, при использовании которых необходимо явно присвоить значение перед ним, иначе оно не будет передано во время компиляции.
  • Для констант, которые изменяются как static, так и final, они должны быть явно назначены при объявлении, иначе они не будут переданы во время компиляции; в то время как константы, которые изменяются только final, могут быть либо явно назначены во время объявления, либо Ему можно явно присвоить значение при инициализации класса, короче говоря, его нужно явно присвоить перед использованием, и система не присвоит ему нулевое значение по умолчанию.
  • Для ссылки на ссылочный тип данных, такой как ссылка на массив, ссылка на объект и т. д., если она используется напрямую без явного присвоения, система присвоит ей нулевое значение по умолчанию, то есть null.
  • Если при инициализации массива каждому элементу массива не присвоено значение, элементам в нем будет присвоено нулевое значение по умолчанию в соответствии с соответствующим типом данных.

Если атрибут ConstantValue существует в таблице атрибутов поля поля класса, то есть модифицируется как final, так и static, то значение переменной будет инициализировано значением, заданным атрибутом ConstValue на этапе подготовки.

фаза синтаксического анализа

Фаза синтаксического анализа — это процесс, посредством которого виртуальная машина заменяет символические ссылки в пуле констант прямыми ссылками. ##этап инициализации На этапе инициализации фактически выполняется Java-код, определенный в классе.

загрузчик классов

С точки зрения виртуальной машины Java существует только два разных загрузчика классов:

  • Загрузчик классов запуска: он реализован на C++ (это ограничено Hotspot, который является виртуальной машиной по умолчанию после JDK1.5, есть много других виртуальных машин, реализованных на языке Java), который является частью самой виртуальной машины.
  • Все другие загрузчики классов: эти загрузчики классов реализованы языком Java, независимо от виртуальной машины, и все они наследуются от абстрактного класса java.lang.ClassLoader, эти загрузчики классов должны быть загружены в память загрузчиком запускаемого класса. Только тогда можно ли загрузить другие классы.

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

  • Загрузчик классов запуска (реализация C)
  • Расширение ClassLoader (ClassLoader)
  • Загрузчик приложений (ClassLoader)
  • Пользовательский загрузчик (ClassLoader)

Иерархическая взаимосвязь этих загрузчиков классов показана на следующем рисунке:

Модель родительского делегирования

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

Как работает модель родительского делегирования

Позвольте мне дать обзор восьми символовпроверить, загрузить снизу
Если класс получает запрос на загрузку класса, он не будет загружать сам запрос, а делегирует запрос на загрузку класса загрузчику родительского класса, который передается слой за слоем, пока не достигнет Bootstrap ClassLoader. Только если загрузчик родительского класса не может загрузить запрос, дочерний загрузчик попытается загрузить его самостоятельно.

Кодовая реализация модели родительского делегирования

Кодовая реализация родительской модели делегирования сконцентрирована в методе loadClass() java.lang.ClassLoader.

  • Сначала проверьте, загружен ли класс, если нет, вызовите метод loadClass() загрузчика родительского класса;
  • Если загрузчик родительского класса пуст, загрузчик класса запуска используется как родительский загрузчик по умолчанию;
  • Если родительский класс не загружается, он вызовет свой собственный метод findClass() после создания исключения ClassNotFoundException.

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

protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    //1 首先检查类是否被加载
    Class c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
             //2 没有则调用父类加载器的loadClass()方法;
                c = parent.loadClass(name, false);
            } else {
            //3 若父类加载器为空,则默认使用启动类加载器作为父加载器;
                c = findBootstrapClass0(name);
            }
        } catch (ClassNotFoundException e) {
           //4 若父类加载失败,抛出ClassNotFoundException 异常后,这个方法就是加载的核心代码
            c = findClass(name);
        }
    }
    if (resolve) {
        //5 再调用自己的findClass() 方法。
        resolveClass(c);
    }
    return c;
}

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

    class NetworkClassLoader extends ClassLoader {
 *         String host;
 *         int port;
 *
 *         public Class findClass(String name) {
 *             byte[] b = loadClassData(name);
 *             return defineClass(name, b, 0, b.length);
 *         }
 *
 *         private byte[] loadClassData(String name) {
 *             // load the class data from the connection
 *             &nbsp;.&nbsp;.&nbsp;.
 *         }
 *     }

Это официальный пример

Сломанная родительская делегация

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

Загрузчик класса контекста потока по умолчанию в Java — это загрузчик системного класса (AppClassLoader).

// Now create the class loader to use to launch the application    
   try {    
       loader = AppClassLoader.getAppClassLoader(extcl);    
   } catch (IOException e) {    
       throw new InternalError(    
   "Could not create application class loader" );    
   }    
        
   // Also set the context class loader for the primordial thread.    
  Thread.currentThread().setContextClassLoader(loader);    

Приведенный выше код взят из конструктора без аргументов Launch() из sun.misc.Launch.

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

Типичным примером является загрузка реализации jndi сторонней библиотеки через контекст потока, не полагаясь на родительское делегирование.

Большинство серверов приложений Java (jboss, tomcat..) также используют contextClassLoader для обработки веб-служб.

конец

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

ежедневные комплименты

Хорошо всем, вышеизложенное является полным содержанием этой статьи. Люди, которые могут видеть это здесь, всенастоящий порошок.

Творить нелегко. Ваша поддержка и признание — самая большая мотивация для моего творчества. Увидимся в следующей статье.

Six Meridians Excalibur | Text [Original] Если в этом блоге есть какие-то ошибки, прошу покритиковать и посоветовать, буду очень признателен!