Что такое runtime data areas
Today we are looking forward to a brief understanding on how the JVM architecture is made and what are the components it holds within. Here we will be understanding the working or say role of all the components. So, lets begin with it!
The JVM architecture is divided into three major portions:
- Class Loader subsytems
- Runtime Data Area
- Execution Engine
The Class Loader Subsystem:
The Java Class Loader loads the classes into the JVM. All virtual machines include one Class Loader which is embedded into the virtual machines.This embedded loader is called the primordial class loader. This class by default implements the default implementations of loadClass().
A class is loaded in two scenarios , when a new bytecode is executed and when a bytecodes makes static references to a class[ we shall discuss this in detail in further topics].
Java’s dynamic class loading functionality is handled by this Class Loader Subsystem. It basically loads, links and initializes the class files at runtime.
The Java Class Loader is based on three principles :
- Delegation principle: This principle forwards a request for the class loading to its parent class loader. It only loads the class if the parent does not find or load a class.
- Visibility principle: This principle gives visibility only to the child class loader to see all the classes are loaded by a parent class, but not vice a versa.
- Uniqueness principle: This principle allows any class to be loaded only once. It is briefly achievable by the Delegation principle, it ensures that no class which are loaded by the parent class is reloaded by the child class.
The types of Class Loader : The Class Loaders are of following types based on from which path has the class been loaded.
- Bootstrap Class Loader: It is the parent of all the Class Loaders. It loads the class files from the Core classes. It is also called as Primordial Class Loader. It loads the class from rt.jar file i.e. jre/lib/rt.jar
- Extensions Class Loader: It is responsible for loading the classes which are inside the ext folder i.e. jre/lib
- System/Application Class Loader: It is responsible for loading of classes from application class path.
The working of JVM is as follows, the System Class Loader delegates load request to the Extension Class Loader, which further delegates request to Bootstrap Class Loader. If the class is detected in the Bootstrap Class Loader, class gets loaded else request again gets transferred to Extension Class Loader; and yet if the class is not found we get a run time exception java.lang.ClassNotFoundException.
The Runtime Data Area:
The Runtime Data Area is split into Method Area, Heap Area, Stack Area, PC Registers, Native Method Stacks.
Method Area: All the class level information i.e. immediate parent name, class name, methods and variables are stored in Method Area. It contains elements which are used in class and in initialization of Objects and Interfaces. Per JVM a single Method Area is allocated. It is a shared resource. It is common across all the threads.
Heap Area: Detailed information of all Objects is stored into the Heap Area. Heap Area when accessed by any thread is further divided into Young Generation, Old Generation and PermGen[Permanent Generation]. When an object is created it first visits the Young Generation(Eden space) and when it gets older it further moves into the Old Generation. All the static and instance variables are stored in PermGen[will talk in detail on this in Garbage Collection Topic]. Per JVM a single Heap Area is allocated. It is also a shared resource, common across all threads.
Stack Area: JVM creates one runtime stack for every single thread. Every block present into the stack is called an activation record / stack frame which holds all the method calls into it. All the local variable calls are stored into the corresponding frame. After the thread terminates, its stack will be destroyed by the JVM. It is not a shared resource. It throws stackOverFlow error when the stack gets full.
PC Register: Stores the address of the current on going execution instruction of a thread. Each thread having specific PC Register. It basically keeps a track on instructions.
Native Method Stack: Native methods are those which are written in languages other than Java. Stores the Native method information in to it. Each thread owns its Native method Stack. It is same as the Stack Area , except that it is used for native methods.
The Execution Engine: This executes the .class (bytecode) files line by line.It further is classified into : interpreter, Just In Time compiler and Garbage Collector. Interpreter interprets the bytecode and then executes the code. The problem that arises here is , the number of times the any method is called that number of times, the interpreter will be needed. As mentioned in our previous article, JIT compiler is helpful in increasing the efficiency of the interpreter. It compiles the entire bytecode and changes it to the Native code, so that whenever interpreter sees a repeated method calls, JIT compiler provides the directly available Native code, so that re-interpretation is not required; there by increasing the efficiency. JIT compiler is an algorithm, that helps us in compiling as well as interpreting. It performs better for redundant code, but can have an additional runtime overhead, while converting the bytecode to native code. Profiler which is the part of JIT compiler is responsible to identify the repeated method calls. JIT compilation is applicable only to repeatedly invoked methods and not for every method. The function of a Garbage Collector is to destroy un-referenced Objects i.e. deallocating any memory which is no longer needed by the running applications.[will have a dedicated article for GC]
The Native Method Interface : The Java Native Interface [JNI] is basically helpful in having interactions with the native method libraries, required for execution i.e. it acts as a bridge[Mediator] for method calls and corresponding native libraries.
The Native Method Libraries: It is a collection of Native Libraries[c|c++], required by execution engine.
That is it for today! for any further clarifications or add ons thisc article could have, please reach out to me.
Native Method Libraries
Native Method Libraries are libraries that are written in other programming languages, such as C, C++, and assembly. These libraries are usually present in the form of .dll or .so files. These native libraries can be loaded through JNI.
- ClassNotFoundExcecption - This occurs when the Class Loader is trying to load classes using Class.forName() , ClassLoader.loadClass() or ClassLoader.findSystemClass() but no definition for the class with the specified name is found.
- NoClassDefFoundError - This occurs when a compiler has successfully compiled the class, but the Class Loader is not able to locate the class file at the runtime.
- OutOfMemoryError - This occurs when the JVM cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.
- StackOverflowError - This occurs if the JVM runs out of space while creating new stack frames while processing a thread.
In this article, we discussed the Java Virtual Machine's architecture and its various components. Often we do not dig deep into the internal mechanics of the JVM or care about how it works while our code is working.
It is only when something goes wrong, and we need to tweak the JVM or fix a memory leak, that we try to understand its internal mechanics.
This is also a very popular interview question, both at junior and senior levels for backend roles. A deep understanding of the JVM helps you write better code and avoid pitfalls related to stack and memory errors.
Thank you for staying with me so far. Hope you liked the article. You can connect with me on LinkedIn where I regularly discuss technology and life. Also take a look at some of my other articles and my YouTube channel. Happy reading. 🙂
Linking
After a class is loaded into memory, it undergoes the linking process. Linking a class or interface involves combining the different elements and dependencies of the program together.
Linking includes the following steps:
Verification: This phase checks the structural correctness of the .class file by checking it against a set of constraints or rules. If verification fails for some reason, we get a VerifyException .
For example, if the code has been built using Java 11, but is being run on a system that has Java 8 installed, the verification phase will fail.
Preparation: In this phase, the JVM allocates memory for the static fields of a class or interface, and initializes them with default values.
For example, assume that you have declared the following variable in your class:
During the preparation phase, JVM allocates memory for the variable enabled and sets its value to the default value for a boolean, which is false .
Resolution: In this phase, symbolic references are replaced with direct references present in the runtime constant pool.
For example, if you have references to other classes or constant variables present in other classes, they are resolved in this phase and replaced with their actual references.
Java Core
9. В чем разница между статическим и динамическим связыванием в Java?
На данный вопрос я уже ответил в этой статье в 18 вопросе про статический и динамический полиморфизм, советую ознакомиться.
10. Можно ли использовать private или protected переменные в interface?
- public — интерфейс предоставляет возможность клиенту взаимодействовать с объектом. Если бы переменные не были общедоступными, у клиентов не было бы к ним доступа.
- static — интерфейсы не могут быть созданы (а точнее, их объекты), поэтому переменная статична.
- final — так как интерфейс используется для достижения 100% абстракции, переменная имеет свой конечный вид (и не будет изменена).
11. Что такое Classloader и для чего используется?
Bootstrap ClassLoader — базовый загрузчик, реализован на уровне JVM и не имеет обратной связи со средой выполнения, так как является частью ядра JVM и написан в машинном коде. Данный загрузчик служит родительским элементом для всех других экземпляров ClassLoader.
В основном отвечает за загрузку внутренних классов JDK, обычно rt.jar и других основных библиотек, расположенных в каталоге $ JAVA_HOME / jre / lib. У разных платформ могут быть разные реализации этого загрузчика классов.
Extension Classloader — загрузчик расширений, потомок класса базового загрузчика. Заботится о загрузке расширения стандартных базовых классов Java. Загружается из каталога расширений JDK, обычно — $ JAVA_HOME / lib / ext или любого другого каталога, упомянутого в системном свойстве java.ext.dirs (с помощью данной опции можно управлять загрузкой расширений).
System ClassLoader — системный загрузчик, реализованный на уровне JRE, который заботится о загрузке всех классов уровня приложения в JVM. Он загружает файлы, найденные в переменном окружении классов -classpath или -cp опции командной строки.
System Classloader пытается найти класс в своем кеше.
1.1. Если класс найден, загрузка успешно завершена.
1.2. Если класс не найден, загрузка делегируется к Extension Classloader-у.
Extension Classloader пытается найти класс в собственном кеше.
2.1. Если класс найден — успешно завершена.
2.2. Если класс не найден, загрузка делегируется Bootstrap Classloader-у.
Bootstrap Classloader пытается найти класс в собственном кеше.
3.1. Если класс найден, загрузка успешно завершена.
3.2. Если класс не найден, базовый Bootstrap Classloader попытается его загрузить.
4.1. Прошла успешно — загрузка класса завершена.
4.2. Не прошла успешно — управление передается к Extension Classloader.
5. Extension Classloader пытается загрузить класс, и если загрузка:
5.1. Прошла успешно — загрузка класса завершена.
5.2. Не прошла успешно — управление передается к System Classloader.
6. System Classloader пытается загрузить класс, и если загрузка:
6.1. Прошла успешно — загрузка класса завершена.
6.2. Не прошла успешно — генерируется исключение — ClassNotFoundException.
12. Что такое Run-Time Data Areas?
PC Register — регистр ПК — локален для каждого потока и содержит адрес инструкции JVM, которую поток выполняет в данный момент.
JVM Stack — область памяти, которая используется как хранилище для локальных переменных и временных результатов. У каждого потока есть свой отдельный стек: как только поток завершается, этот стек также уничтожается. Стоит отметить, что преимуществом stack над heap является производительность, в то время как heap безусловно имеет преимущество в масштабе хранилища.
Native Method Stack — область данных для каждого потока, в которой хранятся элементы данных, аналогичные стеку JVM, для выполнения собственных (не Java) методов.
Heap — используется всеми потоками как хранилище которое содержит объекты, метаданные классов, массивы и т. д., которые создаются во время выполнения. Данная область создается при запуске JVM и уничтожается при завершении ее работы.
Method area — область метода — эта область времени выполнения общая для всех потоков и создается при запуске JVM. Он хранит структуры для каждого класса, такие как пул констант (Runtime Constant Pool — пул для хранения констант), код для конструкторов и методов, данные метода и т. д.
13. Что такое immutable object?
В данной части статьи в 14 и 15 вопросе уже есть ответ на этот вопрос, поэтому ознакамливаетесь не теряя времени зря.
14. В чем особенность класса String?
Это самый популярный объект в Java, который применяют для разнообразных целей. По частоте использования он не уступает даже примитивным типам.
Объект данного класса можно создать без использования ключевого слова new — непосредственно через кавычки String str = “строка”; .
String — это immutable класс: при создании объекта данного класса его данные нельзя изменить (когда вы к некоторой строке добавляете + “другую строку”, как результат вы получите новую, третью строку). Неизменность класса String делает его потокобезопасным.
Класс String финализирован (имеет модификатор final ), поэтому его наследование невозможно.
У String есть свой пул строк, область памяти в heap, которая кеширует создаваемые строковые значения. В этой части серии, в 62 вопросе, я описывал строковой пул.
В Java присутствуют аналоги String , также предназначенные для работы с строками — StringBuilder и StringBuffer , но с тем отличием, что они изменяемые. Подробнее о них вы можете почитать в этой статье.
15. Что такое ковариантность типов?
Для C ++ программист является менеджером памяти, он владеет владельцем каждого объекта и отвечает за весь процесс жизни объекта от создания до завершения (сопоставление пар new-> delete).
Для программистов на Java управление памятью осуществляется виртуальной машиной, а программисты на Java - просто пользователи памяти. Автоматическое управление памятью в JVM значительно облегчает использование пользователем, делая его менее подверженным утечкам памяти или проблемам с переполнением. В то же время, как только происходит утечка памяти или переполнение, ее будет трудно устранить. Поэтому понимание механизма управления памятью JVM является необходимой работой для программистов на Java.
Run-Time Data Areas
JVM определяет множество различных областей данных времени выполнения для использования во время выполнения программы. Некоторые из них создаются при запуске JVM и уничтожаются при выходе из JVM, другие принадлежат потоку, создаются при его создании и уничтожаются при выходе из него.
Регистр счетчика программирования
JVM поддерживает многопоточную работу. Рабочий режим - мультиплексирование с разделением по времени процессора. Чтобы обеспечить его правильное восстановление после переключения потоков, JVM назначает счетчик ПК каждому потоку и каждому потоку Счетчики не влияют друг на друга и хранятся независимо. Мы называем это "частная нить".
Если текущий исполняемый метод не является собственным, значение ПК является адресом его следующей инструкции. Если текущий метод является собственным, регистр ПК не определен.
Единственный случай в этой области памяти, где в JVM нет OutOfMemoryError.
Стеки виртуальных машин Java
Как и счетчик ПК, стеки виртуальных машин Java являются частными потоками и создаются при создании потока.
Стек виртуальной машины Java встроен во фрейм. Когда вызывается метод, создается новый кадр стека, и соответствующий кадр стека уничтожается в конце вызова метода (независимо от того, нормально ли выходит метод или нет).
В стеке хранится такая информация, как таблица локальных переменных, стек операций, динамическая ссылка и выход метода текущего метода в классе.
1) Таблица локальных переменных локальных переменных (Local Variable Array)
Размер таблицы локальных переменных определяется во время компиляции. В ней могут храниться логические, char, byte, short, int, double, float, double, reference (указывающие на адрес объекта кучи ) И типы returnAddress (указывающие на адрес инструкции байт-кода), из которых длинные и двойные данные занимают два последовательныхПространство локальной переменной (неизвестный размер), Остальные типы данных занимают только один. Поэтому размер таблицы локальных переменных зависит только от реализации JVM.
Доступ к таблице локальных переменных осуществляется через индекс, а диапазон значений индекса равен [0, array.length).
2)Operand Stacks
Спецификация виртуальной машины Java определяет два исключения для этой области:
StackOverflowError, JVM генерирует StackOverflowError, когда запрос потока превышает глубину, разрешенную стеками JVM.
OutOfMemoryError, если стеки JVM могут быть динамически расширены (фактически, большинство текущих виртуальных машин Java могут динамически расширяться), когда память не может удовлетворить свой запрос на расширение, она не может применяться для достаточного объема памяти JVM выдает ошибку OutOfMemoryError.
Native Method Stacks
Как видно из названия, стек собственных методов обслуживает собственные методы, и его функция очень похожа на стек виртуальных машин.
Собственные методы - это методы, написанные не на языке Java, которые могут вызываться JVM.
Как и стек виртуальной машины, стек локальных методов также может быть фиксированного размера или динамически расширяемым, и он также будет генерировать исключения StackOverflowError и OutOfMemoryError.
Heap
Куча является общей для потоков, создается при запуске виртуальной машины и используется для хранения объектов и массивов.
В языке Java объекты не удаляются точно (удаляются), а управляются сборщиком мусора, то есть системой автоматического управления памятью, а сборщик мусора в основном обслуживает область кучи. ,
Куча может иметь фиксированный размер или динамически расширяться в соответствии с требованиями к вычислительным ресурсам. Если требование превышает максимальную ситуацию, которую может обеспечить куча, генерируется исключение OutOfMemoryError.
Память кучи физически не требует непрерывного пространства для хранения.
Method Area
Область метода используется потоками и хранит информацию о классе, включая пул констант времени выполнения, данные полей и методов, код метода и конструктора и т. Д.
Область метода логически является частью области кучи и может иметь фиксированный размер или динамически расширяться. Область физической памяти не обязательно должна быть смежной. В отличие от кучи, область метода имеет меньше поведения для сборки мусора и может даже не выполнять сборку мусора.
Если область метода не может удовлетворить требования выделения памяти, генерируется исключение OutOfMemoryError.
Run-Time Constant Pool
Пул констант времени выполнения является частью области метода и используется для хранения различных литералов и ссылок на символы, сгенерированных во время компиляции. Это содержимое будет сохранено в пуле констант времени выполнения после загрузки класса. дюйм
Как и в области методов, когда пул констант не может применяться к памяти, генерируется исключение OutOfMemoryError.
Interpreter
The interpreter reads and executes the bytecode instructions line by line. Due to the line by line execution, the interpreter is comparatively slower.
Another disadvantage of the interpreter is that when a method is called multiple times, every time a new interpretation is required.
Loading
Loading involves taking the binary representation (bytecode) of a class or interface with a particular name, and generating the original class or interface from that.
There are three built-in class loaders available in Java:
The JVM uses the ClassLoader.loadClass() method for loading the class into memory. It tries to load the class based on a fully qualified name.
If a parent class loader is unable to find a class, it delegates the work to a child class loader. If the last child class loader isn't able to load the class either, it throws NoClassDefFoundError or ClassNotFoundException .
Execution Engine
Once the bytecode has been loaded into the main memory, and details are available in the runtime data area, the next step is to run the program. The Execution Engine handles this by executing the code present in each class.
However, before executing the program, the bytecode needs to be converted into machine language instructions. The JVM can use an interpreter or a JIT compiler for the execution engine.
JIT Compiler
The JIT Compiler overcomes the disadvantage of the interpreter. The Execution Engine first uses the interpreter to execute the byte code, but when it finds some repeated code, it uses the JIT compiler.
The JIT compiler then compiles the entire bytecode and changes it to native machine code. This native machine code is used directly for repeated method calls, which improves the performance of the system.
The JIT Compiler has the following components:
- Intermediate Code Generator - generates intermediate code
- Code Optimizer - optimizes the intermediate code for better performance
- Target Code Generator - converts intermediate code to native machine code
- Profiler - finds the hotspots (code that is executed repeatedly)
To better understand the difference between interpreter and JIT compiler, assume that you have the following code:
An interpreter will fetch the value of sum from memory for each iteration in the loop, add the value of i to it, and write it back to memory. This is a costly operation because it is accessing the memory each time it enters the loop.
However, the JIT compiler will recognize that this code has a HotSpot, and will perform optimizations on it. It will store a local copy of sum in the PC register for the thread and will keep adding the value of i to it in the loop. Once the loop is complete, it will write the value of sum back to memory.
Note: a JIT compiler takes more time to compile the code than for the interpreter to interpret the code line by line. If you are going to run a program only once, using the interpreter is better.
Garbage Collector
The Garbage Collector (GC) collects and removes unreferenced objects from the heap area. It is the process of reclaiming the runtime unused memory automatically by destroying them.
Garbage collection makes Java memory efficient because because it removes the unreferenced objects from heap memory and makes free space for new objects. It involves two phases:
- Mark - in this step, the GC identifies the unused objects in memory
- Sweep - in this step, the GC removes the objects identified during the previous phase
Garbage Collections is done automatically by the JVM at regular intervals and does not need to be handled separately. It can also be triggered by calling System.gc() , but the execution is not guaranteed.
The JVM contains 3 different types of garbage collectors:
- Serial GC - This is the simplest implementation of GC, and is designed for small applications running on single-threaded environments. It uses a single thread for garbage collection. When it runs, it leads to a "stop the world" event where the entire application is paused. The JVM argument to use Serial Garbage Collector is -XX:+UseSerialGC
- Parallel GC - This is the default implementation of GC in the JVM, and is also known as Throughput Collector. It uses multiple threads for garbage collection, but still pauses the application when running. The JVM argument to use Parallel Garbage Collector is -XX:+UseParallelGC .
- Garbage First (G1) GC - G1GC was designed for multi-threaded applications that have a large heap size available (more than 4GB). It partitions the heap into a set of equal size regions, and uses multiple threads to scan them. G1GC identifies the regions with the most garbage and performs garbage collection on that region first. The JVM argument to use G1 Garbage Collector is -XX:+UseG1GC
Note: There is another type of garbage collector called Concurrent Mark Sweep (CMS) GC. However, it has been deprecated since Java 9 and completely removed in Java 14 in favour of G1GC.
Java Native Interface (JNI)
At times, it is necessary to use native (non-Java) code (for example, C/C++). This can be in cases where we need to interact with hardware, or to overcome the memory management and performance constraints in Java. Java supports the execution of native code via the Java Native Interface (JNI).
JNI acts as a bridge for permitting the supporting packages for other programming languages such as C, C++, and so on. This is especially helpful in cases where you need to write code that is not entirely supported by Java, like some platform specific features that can only be written in C.
You can use the native keyword to indicate that the method implementation will be provided by a native library. You will also need to invoke System.loadLibrary() to load the shared native library into memory, and make its functions available to Java.
Program Counter (PC) Registers
The JVM supports multiple threads at the same time. Each thread has its own PC Register to hold the address of the currently executing JVM instruction. Once the instruction is executed, the PC register is updated with the next instruction.
Heap Area
All the objects and their corresponding instance variables are stored here. This is the run-time data area from which memory for all class instances and arrays is allocated.
For example assume that you are declaring the following instance:
In this code example, an instance of Employee is created and loaded into the heap area.
The heap is created on the virtual machine start-up, and there is only one heap area per JVM.
Note: Since the Method and Heap areas share the same memory for multiple threads, the data stored here is not thread safe.
Runtime Data Area
There are five components inside the runtime data area:
Let's look at each one individually.
Java Core
9. В чем разница между статическим и динамическим связыванием в Java?
На данный вопрос я уже ответил в этой статье в 18 вопросе про статический и динамический полиморфизм, советую ознакомиться.
10. Можно ли использовать private или protected переменные в interface?
- public — интерфейс предоставляет возможность клиенту взаимодействовать с объектом. Если бы переменные не были общедоступными, у клиентов не было бы к ним доступа.
- static — интерфейсы не могут быть созданы (а точнее, их объекты), поэтому переменная статична.
- final — так как интерфейс используется для достижения 100% абстракции, переменная имеет свой конечный вид (и не будет изменена).
11. Что такое Classloader и для чего используется?
Bootstrap ClassLoader — базовый загрузчик, реализован на уровне JVM и не имеет обратной связи со средой выполнения, так как является частью ядра JVM и написан в машинном коде. Данный загрузчик служит родительским элементом для всех других экземпляров ClassLoader.
В основном отвечает за загрузку внутренних классов JDK, обычно rt.jar и других основных библиотек, расположенных в каталоге $ JAVA_HOME / jre / lib. У разных платформ могут быть разные реализации этого загрузчика классов.
Extension Classloader — загрузчик расширений, потомок класса базового загрузчика. Заботится о загрузке расширения стандартных базовых классов Java. Загружается из каталога расширений JDK, обычно — $ JAVA_HOME / lib / ext или любого другого каталога, упомянутого в системном свойстве java.ext.dirs (с помощью данной опции можно управлять загрузкой расширений).
System ClassLoader — системный загрузчик, реализованный на уровне JRE, который заботится о загрузке всех классов уровня приложения в JVM. Он загружает файлы, найденные в переменном окружении классов -classpath или -cp опции командной строки.
System Classloader пытается найти класс в своем кеше.
1.1. Если класс найден, загрузка успешно завершена.
1.2. Если класс не найден, загрузка делегируется к Extension Classloader-у.
Extension Classloader пытается найти класс в собственном кеше.
2.1. Если класс найден — успешно завершена.
2.2. Если класс не найден, загрузка делегируется Bootstrap Classloader-у.
Bootstrap Classloader пытается найти класс в собственном кеше.
3.1. Если класс найден, загрузка успешно завершена.
3.2. Если класс не найден, базовый Bootstrap Classloader попытается его загрузить.
4.1. Прошла успешно — загрузка класса завершена.
4.2. Не прошла успешно — управление передается к Extension Classloader.
5. Extension Classloader пытается загрузить класс, и если загрузка:
5.1. Прошла успешно — загрузка класса завершена.
5.2. Не прошла успешно — управление передается к System Classloader.
6. System Classloader пытается загрузить класс, и если загрузка:
6.1. Прошла успешно — загрузка класса завершена.
6.2. Не прошла успешно — генерируется исключение — ClassNotFoundException.
12. Что такое Run-Time Data Areas?
PC Register — регистр ПК — локален для каждого потока и содержит адрес инструкции JVM, которую поток выполняет в данный момент.
JVM Stack — область памяти, которая используется как хранилище для локальных переменных и временных результатов. У каждого потока есть свой отдельный стек: как только поток завершается, этот стек также уничтожается. Стоит отметить, что преимуществом stack над heap является производительность, в то время как heap безусловно имеет преимущество в масштабе хранилища.
Native Method Stack — область данных для каждого потока, в которой хранятся элементы данных, аналогичные стеку JVM, для выполнения собственных (не Java) методов.
Heap — используется всеми потоками как хранилище которое содержит объекты, метаданные классов, массивы и т. д., которые создаются во время выполнения. Данная область создается при запуске JVM и уничтожается при завершении ее работы.
Method area — область метода — эта область времени выполнения общая для всех потоков и создается при запуске JVM. Он хранит структуры для каждого класса, такие как пул констант (Runtime Constant Pool — пул для хранения констант), код для конструкторов и методов, данные метода и т. д.
13. Что такое immutable object?
В данной части статьи в 14 и 15 вопросе уже есть ответ на этот вопрос, поэтому ознакамливаетесь не теряя времени зря.
14. В чем особенность класса String?
Это самый популярный объект в Java, который применяют для разнообразных целей. По частоте использования он не уступает даже примитивным типам.
Объект данного класса можно создать без использования ключевого слова new — непосредственно через кавычки String str = “строка”; .
String — это immutable класс: при создании объекта данного класса его данные нельзя изменить (когда вы к некоторой строке добавляете + “другую строку”, как результат вы получите новую, третью строку). Неизменность класса String делает его потокобезопасным.
Класс String финализирован (имеет модификатор final ), поэтому его наследование невозможно.
У String есть свой пул строк, область памяти в heap, которая кеширует создаваемые строковые значения. В этой части серии, в 62 вопросе, я описывал строковой пул.
В Java присутствуют аналоги String , также предназначенные для работы с строками — StringBuilder и StringBuffer , но с тем отличием, что они изменяемые. Подробнее о них вы можете почитать в этой статье.
15. Что такое ковариантность типов?
Для C ++ программист является менеджером памяти, он владеет владельцем каждого объекта и отвечает за весь процесс жизни объекта от создания до завершения (сопоставление пар new-> delete).
Для программистов на Java управление памятью осуществляется виртуальной машиной, а программисты на Java - просто пользователи памяти. Автоматическое управление памятью в JVM значительно облегчает использование пользователем, делая его менее подверженным утечкам памяти или проблемам с переполнением. В то же время, как только происходит утечка памяти или переполнение, ее будет трудно устранить. Поэтому понимание механизма управления памятью JVM является необходимой работой для программистов на Java.
Run-Time Data Areas
JVM определяет множество различных областей данных времени выполнения для использования во время выполнения программы. Некоторые из них создаются при запуске JVM и уничтожаются при выходе из JVM, другие принадлежат потоку, создаются при его создании и уничтожаются при выходе из него.
Регистр счетчика программирования
JVM поддерживает многопоточную работу. Рабочий режим - мультиплексирование с разделением по времени процессора. Чтобы обеспечить его правильное восстановление после переключения потоков, JVM назначает счетчик ПК каждому потоку и каждому потоку Счетчики не влияют друг на друга и хранятся независимо. Мы называем это "частная нить".
Если текущий исполняемый метод не является собственным, значение ПК является адресом его следующей инструкции. Если текущий метод является собственным, регистр ПК не определен.
Единственный случай в этой области памяти, где в JVM нет OutOfMemoryError.
Стеки виртуальных машин Java
Как и счетчик ПК, стеки виртуальных машин Java являются частными потоками и создаются при создании потока.
Стек виртуальной машины Java встроен во фрейм. Когда вызывается метод, создается новый кадр стека, и соответствующий кадр стека уничтожается в конце вызова метода (независимо от того, нормально ли выходит метод или нет).
В стеке хранится такая информация, как таблица локальных переменных, стек операций, динамическая ссылка и выход метода текущего метода в классе.
1) Таблица локальных переменных локальных переменных (Local Variable Array)
Размер таблицы локальных переменных определяется во время компиляции. В ней могут храниться логические, char, byte, short, int, double, float, double, reference (указывающие на адрес объекта кучи ) И типы returnAddress (указывающие на адрес инструкции байт-кода), из которых длинные и двойные данные занимают два последовательныхПространство локальной переменной (неизвестный размер), Остальные типы данных занимают только один. Поэтому размер таблицы локальных переменных зависит только от реализации JVM.
Доступ к таблице локальных переменных осуществляется через индекс, а диапазон значений индекса равен [0, array.length).
2)Operand Stacks
Спецификация виртуальной машины Java определяет два исключения для этой области:
StackOverflowError, JVM генерирует StackOverflowError, когда запрос потока превышает глубину, разрешенную стеками JVM.
OutOfMemoryError, если стеки JVM могут быть динамически расширены (фактически, большинство текущих виртуальных машин Java могут динамически расширяться), когда память не может удовлетворить свой запрос на расширение, она не может применяться для достаточного объема памяти JVM выдает ошибку OutOfMemoryError.
Native Method Stacks
Как видно из названия, стек собственных методов обслуживает собственные методы, и его функция очень похожа на стек виртуальных машин.
Собственные методы - это методы, написанные не на языке Java, которые могут вызываться JVM.
Как и стек виртуальной машины, стек локальных методов также может быть фиксированного размера или динамически расширяемым, и он также будет генерировать исключения StackOverflowError и OutOfMemoryError.
Heap
Куча является общей для потоков, создается при запуске виртуальной машины и используется для хранения объектов и массивов.
В языке Java объекты не удаляются точно (удаляются), а управляются сборщиком мусора, то есть системой автоматического управления памятью, а сборщик мусора в основном обслуживает область кучи. ,
Куча может иметь фиксированный размер или динамически расширяться в соответствии с требованиями к вычислительным ресурсам. Если требование превышает максимальную ситуацию, которую может обеспечить куча, генерируется исключение OutOfMemoryError.
Память кучи физически не требует непрерывного пространства для хранения.
Method Area
Область метода используется потоками и хранит информацию о классе, включая пул констант времени выполнения, данные полей и методов, код метода и конструктора и т. Д.
Область метода логически является частью области кучи и может иметь фиксированный размер или динамически расширяться. Область физической памяти не обязательно должна быть смежной. В отличие от кучи, область метода имеет меньше поведения для сборки мусора и может даже не выполнять сборку мусора.
Если область метода не может удовлетворить требования выделения памяти, генерируется исключение OutOfMemoryError.
Run-Time Constant Pool
Пул констант времени выполнения является частью области метода и используется для хранения различных литералов и ссылок на символы, сгенерированных во время компиляции. Это содержимое будет сохранено в пуле констант времени выполнения после загрузки класса. дюйм
Как и в области методов, когда пул констант не может применяться к памяти, генерируется исключение OutOfMemoryError.
Stack Area
Whenever a new thread is created in the JVM, a separate runtime stack is also created at the same time. All local variables, method calls, and partial results are stored in the stack area.
If the processing being done in a thread requires a larger stack size than what's available, the JVM throws a StackOverflowError .
For every method call, one entry is made in the stack memory which is called the Stack Frame. When the method call is complete, the Stack Frame is destroyed.
The Stack Frame is divided into three sub-parts:
- Local Variables – Each frame contains an array of variables known as its local variables. All local variables and their values are stored here. The length of this array is determined at compile-time.
- Operand Stack – Each frame contains a last-in-first-out (LIFO) stack known as its operand stack. This acts as a runtime workspace to perform any intermediate operations. The maximum depth of this stack is determined at compile-time.
- Frame Data – All symbols corresponding to the method are stored here. This also stores the catch block information in case of exceptions.
For example assume that you have the following code:
In this code example, variables like answers and score are placed in the Local Variables array. The Operand Stack contains the variables and operators required to perform the mathematical calculations of subtraction and division.
Note: Since the Stack Area is not shared, it is inherently thread safe.
Class Loader
When you compile a .java source file, it is converted into byte code as a .class file. When you try to use this class in your program, the class loader loads it into the main memory.
The first class to be loaded into memory is usually the class that contains the main() method.
There are three phases in the class loading process: loading, linking, and initialization.
Initialization
Initialization involves executing the initialization method of the class or interface (known as ). This can include calling the class's constructor, executing the static block, and assigning values to all the static variables. This is the final stage of class loading.
For example, when we declared the following code earlier:
The variable enabled was set to its default value of false during the preparation phase. In the initialization phase, this variable is assigned its actual value of true .
Note: the JVM is multi-threaded. It can happen that multiple threads are trying to initialize the same class at the same time. This can lead to concurrency issues. You need to handle thread safety to ensure that the program works properly in a multi-threaded environment.
Native Method Stacks
The JVM contains stacks that support native methods. These methods are written in a language other than the Java, such as C and C++. For every new thread, a separate native method stack is also allocated.
Анимация: Глубокий анализ JVM Runtime Runtime Data Direct Exclusive Plase
Долгое время не было запланировано, я думал о объяснении очков знаний, пусть все узнают знания и могут углубить память. Думать долгое время, я думаю о форме анимации. Я впервые попробовал, я также надеюсь, что все сделают более ценные комментарии. Последующие могут добавлять истории и совместное использование с вами в виде пояснений записи.
Сегодня давайте посмотрим на область данного времени выполнения JVM, эта часть этого составляет 90% собеседования.
Виртуальная машина Java
JVM : Просто Java Virtual Machine, во время программы Java работает, память, которую она удалось в несколько различных областей данных, которые создаются с JVM Startup, а некоторые, как пользовательская тема, начинает устанавливать и уничтожать его с концами.
Базовая модель памяти JVM Runtime выглядит следующим образом:
Вышеуказанное изображение показывает Секретация виртуальной машины JVM Отказ Обратите внимание, что различные виртуальные машины имеют некоторый доступ, Oracle, когда публикуют новую версию Java, могут выполнять определенные оптимизации и улучшения для JVM, например, в версии JDK8, область метода удаляется, заменена Metaspace (пространство метаданных)
С фигуры выше, мы можем видеть, что область памяти в основном разделена на две части:
1. Эксклюзивная область
включать:Счетчик команд,Виртуальный стек,Местный квадратный стек
2. Область обмена потоками
В том числе:Метод области,куча
Давайте начнем с темы эксклюзивной области.
Счетчик команд
Счетчик команд : Меньшее пространство памяти записывает индикатор строки, выполненного текущей резьбой, который означает, что адрес следующей инструкции, командный код для выполнения. Следующая инструкция прочитана исполнительным двигателем.
Переводчик байтового кода работает, изменив значение счетчика, изменяя значение этого счетчика, и переводится его в фиксированную операцию, чтение инструкции, ветви, цикл, прыжка в соответствии с этими операциями.,
Обработка исключений, восстановление резьбы и т. Д. Нужно полагаться на этот счетчик для завершения.
Характеристики
1. Если тема выполняется, представляет собой метод Java, этот счетчик записывается в приведенном элементе кода символов виртуальной машины.
2. Если нативный метод выполняется, это значение технике пустое (не определено).
Поскольку нативный метод заключается в том, что Java вызывает локальную библиотеку C / C ++ непосредственно через JNI, может быть аппроксимирована, что нативный метод эквивалентен C / C ++, подверженным воздействию Java, Java называется C / C + + Способ, вызывая этот интерфейс.
Поскольку этот метод достигается через C / C ++ вместо Java. Таким образом, естественно, не в состоянии сделать соответствующий байт-код, а распределение памяти C / C ++ определяется собственным языком, а не JVM.
3. Эта область памяти является единственной областью, которая не указывает никакого состояния OOM в спецификации виртуальной машины Java.
эффект
Multi-Threaded JVM достигается вращением срезы с временем CPU (то есть резьбовой поворотный стол и присвоение времени выполнения процессора) алгоритма. То есть нить может быть приостановлена во время выполнения, а другой поток получает выполнение в другом потоке.
Когда в ответной ните достигает временного нарезания, необходимо продолжать выполнять из подвешенного места, вы должны знать, какое положение выполняется в прошлый раз, в JVM выполняют резьбу через счетчик программы Код байта.
Следовательно, счетчик программы является характеристиками изоляции потоков, то есть каждая нить работает с собственным независимым счетчиком. Счетчик программы между различными потоками не влияет на друг друга, независимо от магазинов.
Давайте посмотрим на пример ниже:
выполненный:javap -c JavaPTest.class
Javap - это повторный анализатор с JDK. Его роль основана на файле класса Bytecode, отражает область кода (инструкция по сборке), локальные переменные, таблицу исключения и таблицу сочетания кода, постоянный пул и т. Д. В текущем классе.
Давайте посмотрим, как записывается счетчик программы, а ниже виртуальной машины снова разлагается.
Виртуальный стек
Виртуальный стек : Выполняется модель памяти метода Java. Всякий раз, когда запуск нового потока, виртуальные машины Java выделяют для него стек Java.
Java сохраняет текущий статус нити с кадром стека.
Виртуальная машина выполняет только две операции на стеке Java: стек или из стека кадров стека.
Стек Java выбрасывает
Stackoverferroor и OutofMemoryError являются ненормальными.
Стек кадр: На метод Создать один при выполнении Стек кадр , Магазин Частичная переменная таблица , Рабочий стек,Динамическая ссылка, метод выхода И другая информация.
Каждый метод вызывается процессом, соответствующим кадрам стека из фонтана до из стека на виртуальной машине.
Мы сравниваем код выше, когда нить вызывает основную функцию, на этот раз вы создаете кадр стека, чтобы нажать верхнюю часть стека. Когда основная функция вызывает функцию CALC, система создаст кадр кадра в верхней части. На следующем рисунке показано.
Частичная переменная таблица : Непрерывное пространство памяти, используется для хранения параметров метода, а также локальных переменных, определенных в способе, сохраненные типы данных, известные во время компиляции (восемь основных типов, а также ссылки на объекты (типы ссылок), типы returnAddress.
Его минимальная локальная табличного пространства для таблицы переменных является слот, виртуальная машина не указывает размер слота, но в JVM данные длинные и двойные данные четко определены как 64 бита, эти два типа учетной записи для 2 слотов, других базовых Типы фиксированного оккупации 1 слот.
Тип ссылки: отличается от базового типа, он не эквивалентен к нему, даже строку, внутренняя часть также является массивом CHAR, который может указывать на указатель положения пуска объекта, или указывать на ручку объекта или другого объекта, связанного с объект. Положение.
Следует отметить, что пространство памяти, требуемое таблицу локальной переменной, выделяется в период компиляции. При вводе метода этот метод должен быть выделен в стеке на все локальные пространства переменных, полностью определены, а локальная переменная не является Изменено во время работы метода. Переменная таблица размера.
Если это метод экземпляра (нестатический метод), слот 0-го индекса в локальной таблице переменных представляет собой ссылку на экземпляр объекта, к которому относится метод «» this «Остальные параметры расположены в порядке таблицы параметров, занимая локальные переменные из 1 слота
Работа подсчет (Stack Operand) также часто упоминается как операционный стек, который является первым в стеке.
Когда метод просто начинает выполнять, действующий корпус этого метода пуст. Во время реализации метода будет различные инструкции по базовому коде для записи и извлечения содержимого в стеке подсчета операций, то есть стека / факт.
Например, когда арифметическая операция выполняется путем работы числа стека или при вызове других методов, он передается через стек оператора.
Например, целое добавление инструкции Bytecode IADD двух элементов, которые наиболее близки к верхней части стека в операнде при работе хранятся два значения типа INT. Когда эта инструкция выполняется, эти два значения INT меблирован и добавлен, то дополнительный результат включен.
Ниже мы используем форму анимации, чтобы сломать код только сейчас:
bipush 100 Нажмите однобайтовое постоянное значение 100 (-128 ~ 127) до верхней части оператора
istore_1 Храните операнд оперативной стоп-сигнала Value INT во вторую локальную переменную
sipush 200 Нажмите короткое целое число 200 (-32768 ~ 32767) на вершину операнда
istore_2 Депозит оператор Stack Top Int Value в третью частичную переменную
sipush 300 Нажмите короткое целое число 300 (-32768 ~ 32767) в операнд
istore_3 Поместите значение Topand Stack Top INT в четвертую локальную переменную
iload_1 Нажмите вторую частичную переменную типа int в верхней части оператора
iload_2 Нажмите на третий тип введите частичную переменную в верхнюю часть операнда
iadd Добавьте верхние два значения типа INT и нажмите результат в стек
iload_3 Нажмите четвертую локальную переменную INT в верхнюю часть операнда
imul Поместите два верхних значения типа int и нажмите результат в верхнюю часть стека
ireturn Возвращает INT из текущего метода
Динамически подключен
Каждый кадр стека содержит ссылку на метод кадра стека в пуле постоянного времени выполнения, удерживая эту ссылку, предназначено для поддержки динамического соединения в вызове метода.
Метод возврата адреса
Когда метод начинает выполнять, могут быть выведены только два способа, один - это инструкция Bytecode, которая встречается методом; один является ненормальностью, и это исключение не обрабатывается в способе.
Независимо от метода выхода, после того, как метод выходит, необходимо вернуться к способу, вызываемую методом, программа может продолжать выполнять, способ может потребоваться сохранить некоторую информацию в кадре стека, чтобы помочь восстановить свой метод верхнего уровня. . Статус.
Как правило, метод счетчика программы звонящего может быть использован в качестве нормального выхода.Обратный адресЭто значение счетчика, вероятно, сохраняется в кадре стека. Когда метод ненормальный, обратный адрес должен быть определен таблицей процессора исключений, и эта часть информации, как правило, не сохраняется в кадре стека.
Процесс выхода на метод фактически эквивалентен выводу текущей структуры стека из стека, поэтому операция, которая может быть выполнена при выходе, является:Восстановление локальной таблицы переменных и стоп оператора метода верхнего уровня верхнего уровня, нажмите значение возвращаемого значения (если есть) в стопку подсчета оператора в кадре стека вызывающего абонента, отрегулируйте значение счетчика программы, чтобы указать на метод метода. Инструкция.
Местный квадратный стек
Местный квадратный стек (Нативные методы стеки) Роль виртуальной машины Java очень похожа, виртуальная домашняя работа Java используется для управления вызовом метода Java, а стек локального метода используется для управления вызовом локального метода.
Язык, используемый в спецификации виртуальной машины, языком, используемый в стеке локального метода, метод использования и структура данных не являются обязательными, поэтому конкретная виртуальная машина может быть свободной для его реализации.
Метод Navtive заключается в том, что Java вызывает локальную библиотеку C / C ++ непосредственно через JNI, что можно считать, что нативный метод эквивалентен C / C ++, подверженным воздействию Java, а Java вызывается к C / C ++ Метод, вызывая этот интерфейс.
Когда нить вызывает метод Java, виртуальная возможность создает кадру стека и нажимает виртуальную машину Java. Однако, когда он называется нативным методом, виртуальная возможность сохраняет не измененный стек виртуальной машины Java, и не передает в новую кадру стека на виртуальной машине Java, которая просто просто подключается и напрямую вызывает указанный нативный метод.,
Например, мы часто используем систему. CurrentTimeMillis (); это локальный метод
public static native long currentTimeMillis();
Характеристики
1. Локальный метод также может получить доступ к области данных времени работы виртуальной машины через интерфейс локального метода.
2. Это может даже напрямую использовать регистры в локальном процессоре
3. Выделите любое количество памяти непосредственно из стопки локальной памяти
4. Местный квадратный стек также бросит
Stackoverferroor и OutofMemoryError являются ненормальными.
Благодаря проблеме, сегодня мы расскажем о нескольких точках знаний эксклюзивных областей, я буду использовать способ изучения области метода и кучи Java о том, как создавать экземпляры объектов. Пожалуйста, не переключайтесь.
Длинные прессы подписываются более замечательными ▼
Если у вас есть урожай, вы смотрите на него, искреннее спасибо
Siben Nayak
Whether you have used Java to develop programs or not, you might have heard about the Java Virtual Machine (JVM) at some point or another.
JVM is the core of the Java ecosystem, and makes it possible for Java-based software programs to follow the "write once, run anywhere" approach. You can write Java code on one machine, and run it on any other machine using the JVM.
JVM was initially designed to support only Java. However, over the time, many other languages such as Scala, Kotlin and Groovy were adopted on the Java platform. All of these languages are collectively known as JVM languages.
In this article, we will learn more about the JVM, how it works, and the various components that it is made of.
Before we jump into the JVM, let's revisit the concept of a Virtual Machine (VM).
A virtual machine is a virtual representation of a physical computer. We can call the virtual machine the guest machine, and the physical computer it runs on is the host machine.
A single physical machine can run multiple virtual machines, each with their own operating system and applications. These virtual machines are isolated from each other.
In programming languages like C and C++, the code is first compiled into platform-specific machine code. These languages are called compiled languages.
On the other hand, in languages like JavaScript and Python, the computer executes the instructions directly without having to compile them. These languages are called interpreted languages.
Java uses a combination of both techniques. Java code is first compiled into byte code to generate a class file. This class file is then interpreted by the Java Virtual Machine for the underlying platform. The same class file can be executed on any version of JVM running on any platform and operating system.
Similar to virtual machines, the JVM creates an isolated space on a host machine. This space can be used to execute Java programs irrespective of the platform or operating system of the machine.
The JVM consists of three distinct components:
Let's take a look at each of them in more detail.
Method Area
All the class level data such as the run-time constant pool, field, and method data, and the code for methods and constructors, are stored here.
If the memory available in the method area is not sufficient for the program startup, the JVM throws an OutOfMemoryError .
For example, assume that you have the following class definition:
In this code example, the field level data such as name and age and the constructor details are loaded into the method area.
The method area is created on the virtual machine start-up, and there is only one method area per JVM.
Читайте также: