что такое runtime data areas
Java Virtual Machine Run-Time Data Areas
Summary:
This article contains…
Runtime data areas :
Java virtual machine defines various run-time data areas, Mainly these are part of Stack and Heap.
Basic rule of storing java program in memory is,
Further exploring these, list of run-time data areas in java virtual machine are,
in which some are created on java virtual machine start up and some are per thread which are created on when a thread is created and destroy when thread completes.
Details of runtime data areas :
Program counter register :
We know that JVM can support many thread of execution at once. Each JVM thread has its own PC Register.
At any point of time while executing the code of single method (referred as current method), if it is not a native method, pc register address of JVM instruction currently being executed. For native method, value of pc register is undefined.
Java virtual machine stacks :
Each JVM thread has a private JVM stack, created at the time of thread creation.
JVM stack holds data as a Frame, when a new method will be invoked a frame will be pushed into the jvm stack and popped when method execution completes. No other data, except frame, can be push/popped into JVM stack.
Frames :
Frames are used to store partial results, return value from method, perform dynamic linking and dispatch exceptions.
Lifetime of a frame is equal to method execution time, A frame will be pushed to JVM stack when a method will be invoked and distroyed when method execution completes.
At a point of time, Only one frame at a given time can be in active state per thread, which is frame for function being executed.
Each frame has its own Array of local variables, Operand stack and Reference to run-time constant pool.
Array of local variables :
All local variables of method are stored in this array, single local variable can hold any value of type byte, char, short, int, float, reference, return address and boolean while pair of local variable can hold long and double.
local variables are also used to pass parameters when method is invoked. Where local variable 0 is always used to pass reference of object on which instance method is invoked. (this) Any other parameters will be stored from 1.
Operand stack :
Operand stack holds the operand used by operators to perform operations. Each entry on the operand stack can hold a value of any Java Virtual Machine type.
Java Virtual Machine instructions take operands from the operand stack, operate on them, and push the result back onto the operand stack. The operand stack is also used to prepare parameters to be passed to methods and to receive method results.
For example, iadd instruction will add two integer values, so it will pop top two integer values from operand stack and will push result into operand stack after adding them.
Reference to runtime constant pool (Dynamic linking) :
In class file structure, flow of method that will be invoked and variable to be accessed is stored as symbolic reference. Dynamic linking translates this symbolic reference to concrete method reference and loads the class as required. This reference to runtime constant pool is stored in frame to perform dynamic linking at run-time.
Heap :
Heap is a runtime data area in memory where Objects, Instance variable and Arrays are stored. Heap memory storage may be of fixed size or may be expanded as required by computation, and this memory does not need to be contiguous.
Heap is created at virtual machine startup and Objects which are no more referenced will be deallocated from memory by automatic garbage collector, objects are never explicitly deallocated.
Method area :
Method area is created on virtual machine startup, shared among all java virtual machine threads and it is logically part of heap area. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors.
This can be of fixed size or can be expanded as per requirement of computation.
Run-time constant pool :
Run-time constant pool is per class/interface structure, It is runtime representation of constant_pool table generated at compile time which is stored in class file.
Constant pool contains several literal values or symbolic references that will be resolved at runtime. Runtime constant pool for class/interface is allocated from method area and constructed when class or interface is created by JVM.
See below image of JVM Runtime Data areas.
Exceptional condition in JVM runtime data areas :
There are two exceptions associated with JVM runtime data areas. OutOfMemoryError and StackOverflowError.
OutOfMemoryError is applicable for all of the above listed except PC register. OutOfMemoryError will be thrown if memory expansion of any of the memory area will be attempted but enough memory is not available to allocate.
StackOverflowError is applicable for Native Method Stack and Java Virtual Machine Stack. StackOverflowError will be thrown If the computation in a thread requires a larger stack than is permitted.
Monitor JVM Runtime data areas :
You can check JVM runtime memory allocation using JConsole (Java monitoring and management console)
JConsole window : You can select type of run-time data area from chart dropdown menu.
This was about run-time data areas in JVM which will help you to understand memory allocation and topics like argument passing, polymorphism, threads, exceptions, and garbage collection.
You can always clone the executable code of article posted on Java By Examples from github.com
Repository URL : https://github.com/ksarsecha/java8_in.git
More articles will be available soon on Java and SCJP.
Русские Блоги
JVM Run-Time Data Areas
Run-Time Data Areas
JVM определяет множество различных областей данных времени выполнения для использования во время выполнения программы. Некоторые из них создаются при запуске JVM и уничтожаются при выходе из JVM, другие принадлежат потоку, создаются при его создании и уничтожаются при выходе из него.
Стеки виртуальных машин 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.
Method Area
Область метода используется потоками и хранит информацию о классе, включая пул констант времени выполнения, данные полей и методов, код метода и конструктора и т. Д.
Область метода логически является частью области кучи и может иметь фиксированный размер или динамически расширяться. Область физической памяти не обязательно должна быть смежной. В отличие от кучи, область метода имеет меньше поведения для сборки мусора и может даже не выполнять сборку мусора.
Если область метода не может удовлетворить требования выделения памяти, генерируется исключение OutOfMemoryError.
Run-Time Constant Pool
Пул констант времени выполнения является частью области метода и используется для хранения различных литералов и ссылок на символы, сгенерированных во время компиляции. Это содержимое будет сохранено в пуле констант времени выполнения после загрузки класса. дюйм
Как и в области методов, когда пул констант не может применяться к памяти, генерируется исключение OutOfMemoryError.
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.
What is a Virtual Machine?
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.
What is the Java Virtual Machine?
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.
Java Virtual Machine Architecture
The JVM consists of three distinct components:
Let’s take a look at each of them in more detail.
Class Loader
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.
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 .
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:
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:
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.
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:
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.
Runtime Data Area
There are five components inside the runtime data area:
Let’s look at each one individually.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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:
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:
The JVM contains 3 different types of garbage collectors:
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.
Native Method Libraries
Common JVM Errors
Conclusion
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. 🙂
Staff Software Engineer @ Intuit, ex-Amazon, Intel • Cloud Architect • Innovator and Builder • Blogger • Speaker • Love Coding and Building Distributed Systems
If you read this far, tweet to the author to show them you care. Tweet a thanks
Learn to code for free. freeCodeCamp’s open source curriculum has helped more than 40,000 people get jobs as developers. Get started
freeCodeCamp is a donor-supported tax-exempt 501(c)(3) nonprofit organization (United States Federal Tax Identification Number: 82-0779546)
Donations to freeCodeCamp go toward our education initiatives and help pay for servers, services, and staff.
Что такое runtime data areas
4 contributors
Users who have contributed to this file
За что отвечает JVM:
JVM работает с 2мя типами данных: примитивные типы (primitive types) и ссылочные типы (reference types).
Примитивы
Типы ссылок и значения
Существует три типа ссылочных типов: типы классов, типы массивов и типы интерфейсов. Их значения являются ссылками на динамически создаваемые экземпляры классов, массивы или экземпляры классов, которые реализуют интерфейсы соответственно.
Загрузчик классов является частью JRE, которая динамически загружает Java классы в JVM. Обычно классы загружаются только по запросу. Система исполнения в Java не должна знать о файлах и файловых системах благодаря загрузчику классов. Делегирование является важной концепцией, которую выполняет загрузчик. Загрузчик классов отвечает за поиск библиотек, чтение их содержимого и загрузку классов, содержащихся в библиотеках. Эта загрузка обычно выполняется «по требованию», поскольку она не происходит до тех пор, пока программа не вызовет класс. Класс с именем может быть загружен только один раз данным загрузчиком классов.
При запуске JVM, используются три загрузчика классов:
Загрузчик классов выполняет три основных действия в строгом порядке:
Пользовательский загрузчик классов
Загрузчик классов написан на Java. Поэтому возможно создать свой собственный загрузчик классов, не понимая тонких деталей JVM. У каждого загрузчика классов Java есть родительский загрузчик классов, определенный при создании экземпляра нового загрузчика классов или в качестве системного загрузчика классов по умолчанию для виртуальной машины.
Что делает возможным следующее:
Области данных времени выполнения
Run-Time Data Areas. JVM выделяет множество областей данных во время выполнения, которые используются во время выполнения программы. Некоторые участки данных созданы JVM во время старта и уничтожаются во время её выключения. Другие создаются для каждого потока и уничтожаются, когда поток уничтожается.
The pc Register (PCR)
Виртуальная машина Java может поддерживать много потоков исполнения одновременно. Каждый поток виртуальной машины Java имеет свой собственный регистр PC (program counter). В любой момент каждый поток виртуальной машины Java выполняет код одного метода, а именно текущий метод для этого потока. Если этот метод не является native, регистр pc содержит адрес инструкции виртуальной машины Java, выполняемой в настоящее время.
Коротко говоря: для одного потока, существует один PCR, который создается при запуске потока. PCR хранит адрес выполняемой сейчас инструкции JVM.
Java Virtual Machine Stacks
Каждый поток в JVM имеет собственный стек, созданный одновременно с потоком. Стек в JVM хранит frames. Cтеки в JVM могут иметь фиксированный размер или динамически расширяться и сжиматься в соответствии с требованиями вычислений.
Heap
Method Area
JVM имеет область методов, которая является общей для всех потоков. Она хранит структуры для каждого класса, такие как пул констант, данные полей и методов, а также код для методов и конструкторов, включая специальные методы, используемые при инициализации классов и экземпляров, и инициализации интерфейса. Хотя область метода является логически частью кучи, простые реализации могут не обрабатываться сборщиком мусора. Область метода может иметь фиксированный размер или может быть расширена в соответствии с требованиями вычислений и может быть сокращена, если большая область метода становится ненужной.
Run-Time Constant Pool
A run-time constant pool существует для каждого класса или интерфейса в рантайме и представленно constant_pool таблицей в *.class файле. Он содержит несколько видов констант: от числовых литералов, известных во время компиляции, до ссылок на методы и поля, которые должны быть разрешены во время выполнения. Сам run-time constant pool выполняет функцию, аналогичную функции таблицы символов для обычного языка программирования, хотя он содержит более широкий диапазон данных, чем типичная таблица символов. Каждый run-time constant pool отделён от JVM’s method area. JVM создаёт run-time constant pool вместе с созданием class или interface.
Native Method Stacks
Реализация виртуальной машины Java может использовать обычные стеки, обычно называемые «стеки Си», для поддержки native methods (методов, написанных на языке, отличном от языка программирования Java).
Frame используется для хранения данных и частичных результатов, а также для выполнения динамического связывания, возврата значений для методов и отправки исключений. Новый frame создается каждый раз, когда вызывается метод. Frame уничтожается, когда завершается вызов метода, является ли это завершение нормальным или резким (он генерирует неперехваченное исключение). Frames выделяются из стека потока, создающего frame. Каждый frame имеет свой собственный массив локальных переменных, свой собственный стек операндов и ссылку на пул констант во время выполнения класса текущего метода. Размеры массива локальных переменных и стека операндов определяются во время компиляции и предоставляются вместе с кодом для метода, связанного с фреймом. Таким образом, размер структуры данных, frame-а зависит только от реализации виртуальной машины Java, и память для этих структур может быть выделена одновременно при вызове метода.
Frame перестает быть текущим, если его метод вызывает другой метод или если его метод завершается. Когда метод вызывается, новый frame создается и становится текущим, когда управление переходит к новому методу. При возврате метода текущий frame передает результат вызова метода, если таковой имеется, в предыдущий frame. Текущий frame затем отбрасывается, так как предыдущий frame становится текущим. Обратите внимание, что frame, созданный потоком, является локальным для этого потока и на него не может ссылаться ни один другой поток.
Локальные переменные
Каждый frame содержит массив переменных, известных как его локальные переменные. Длина массива локальных переменных frame определяется во время компиляции и предоставляется в двоичном представлении класса или интерфейса вместе с кодом для метода, связанного с frame-ом. Единичная локальная переменная может хранить значение типа: boolean, byte, char, short, int, float, reference, or returnAddress. Пара локальных переменных может хранить значение типов: long или double.
Локальные переменные адресуются путем индексации. Индекс первой локальной переменной равен нулю.
Значение типа long или типа double занимает две последовательные локальные переменные.
JVM использует локальные переменные для передачи параметров при вызове метода. При вызове метода класса все параметры передаются в последовательных локальных переменных, начиная с локальной переменной 0. При вызове метода экземпляра локальная переменная 0 всегда используется для передачи ссылки на объект, для которого вызывается метод экземпляра (this в Java). Любые параметры впоследствии передаются в последовательных локальных переменных, начиная с локальной переменной 1.
Стеки операндов (Operand Stacks)
Стек операнда пуст при создании frame-a, который его содержит. JVM предоставляет инструкции для загрузки констант или значений из локальных переменных или полей в стек операндов. Другие инструкции JVM берут операнды из стека операндов, оперируют с ними и помещают результат обратно в стек операндов. Стек операндов также используется для подготовки параметров для передачи в методы и для получения результатов метода.
Для примера, инструкция iadd суммирует два int-вых значения. От стека операндов требуется, чтобы два int-вых значения были наверху стека. Значения удаляются из стека, операция pop. Суммируются и их сумма помещается в стек операндов.
Динамическое связывание (Dynamic Linking)
Каждый frame содержит ссылку на run-time constant pool для типа текущего метода для поддержки динамического связывания кода метода. Доступ к вызываемым методам и переменным осуществляется через символические ссылки из class файла. Динамическое связывание преобразует эти символьные ссылки на методы в конкретные ссылки на методы, загружая классы по мере необходимости для разрешения пока еще не определенных символов, и преобразует обращения к переменным в соответствующие смещения в структурах хранения, связанных с расположением этих переменных во время выполнения.
Позднее связывание методов и переменных вносит изменения в другие классы, которые метод использует с меньшей вероятностью нарушить этот код.
Нормальное завершение вызова метода
Вызов метода завершается нормально, если этот вызов не вызывает исключение, либо непосредственно из JVM, либо в результате выполнения явного оператора throw. Если вызов текущего метода завершается нормально, то значение может быть возвращено вызывающему методу. Это происходит, когда вызванный метод выполняет одну из инструкций возврата, выбор которых должен соответствовать типу возвращаемого значения (если оно есть).
Текущий frame используется в этом случае для восстановления состояния инициатора, включая его локальные переменные и стек операндов, с соответствующим образом увеличенным программным счетчиком инициатора, чтобы пропустить инструкцию вызова метода. Затем выполнение обычно продолжается в frame вызывающего метода с возвращенным значением (если оно есть), помещаемым в стек операндов этого frame.
Резкое завершение вызова метода
Вызов метода завершается преждевременно, если при выполнении инструкции JVM в методе выдает исключение, и это исключение не обрабатывается в методе. Выполнение команды throw также приводит к явному выбрасыванию исключения, и, если исключение не перехватывается текущим методом, приводит к неожиданному завершению вызова метода. Вызов метода, который завершается внезапно, никогда не возвращает значение своему вызывающему.
Байт-код, назначенный run-time data areas, будет выполнен execution engine. Механизм выполнения считывает байт-код и выполняет его по частям.
Interpreter
Интерпретатор интерпретирует байт-код быстро, но выполняется медленно. Недостаток интерпретатора заключается в том, что, когда один метод вызывается несколько раз, каждый раз требуется новая интерпретация.
JIT Compiler
JIT-компилятор устраняет недостатки интерпретатора. Механизм выполнения будет использовать помощь интерпретатора при преобразовании байт-кода, но когда он находит повторный код, он использует JIT-компилятор, который компилирует весь байт-код и изменяет его на собственный код. Этот нативный код будет использоваться непосредственно для повторных вызовов методов, которые улучшают производительность системы.