вводить
Стек виртуальной машины Java является частным потоком и синхронизируется с циклом объявления потока. Стек виртуальной машины описывает модель памяти выполнения метода Java, и каждое выполнение метода создаеткадр стекакадр стека содержит таблицу локальных переменных, стек операндов, динамическую ссылку, выход из метода и т. д.
стек и кадр стека
Каждый метод выполняется до выполнения, а кадр стека соответствует процессу от стека к четвертому в виртуальной машине. Кадр стека стека виртуальной машины Java — это кадр стека текущего метода выполнения. Регистр ПК будет указывать на этот адрес. Когда этот метод вызывает другие методы, будет создан новый фрейм стека.Этот новый фрейм стека будет подчиняться вершине стека виртуальной машины Java, которая является текущим активным стеком, и только текущим активным стеком локальных переменных. кадр стека завершается, кадр стека удаляется, предыдущий кадр стека становится активным стеком, возвращаемое значение кадра стека перед удалением изменяется на один операнд этого кадра стека.
кадр стека
Фрейм стека (Stack Frame) — это структура данных, используемая для поддержки виртуальной машины при вызове и выполнении метода, и это элемент стека стека виртуальной машины (Virtual Machine Stack) области данных среды выполнения виртуальной машины. Фрейм стека хранит таблицу локальных переменных метода, стек операндов, динамическое соединение и адрес возврата метода, а также другую информацию. Первый метод соответствует процессу помещения кадра стека в стек в стеке виртуальной машины от начала вызова до завершения выполнения. Каждый кадр стека включает в себя таблицу локальных переменных, стек операндов, динамическую ссылку, адрес возврата метода и некоторую дополнительную дополнительную информацию. При компиляции кода стекРазмер таблицы локальных переменных и глубина стека операндов во фрейме полностью определены и записаны в атрибут Code таблицы методов, поэтому объем памяти, который необходимо выделить для фрейма стека, не будет зависеть от переменные данные во время выполнения программы влияют, но зависит только от реализации конкретной виртуальной машины.Цепочка вызовов методов в потоке может быть очень длинной, при этом многие методы одновременно обрабатывают состояние выполнения. Для механизма выполнения в активном потоке действителен только кадр стека в верхней части стека виртуальной машины, который называется текущим кадром стека (Current Stack Frame), а метод, связанный с этим кадром стека, называется текущим. метод (текущий метод). Все инструкции байт-кода, запускаемые ссылкой выполнения, работают только с текущим кадром стека. Концептуальная структура кадра стека показана на следующем рисунке:
таблица локальных переменных
- Таблица локальных переменных — это место для хранения значений переменных, которое используется для хранения параметров метода и локальных переменных, определенных внутри метода. Когда java компилируется в файл класса, емкость максимальной таблицы локальных переменных, которую должен выделить метод, определяется в элементе данных max_locals атрибута Code метода.
- Емкость таблицы локальных переменных основана на слоте переменной (Slot) как наименьшей единице.Слот в 32-разрядной виртуальной машине может хранить типы данных в пределах 32 бит (4 байта) ( boolean, byte, char, short, int, float, reference и returnAddress восемь)
- Для 64-битных типов данных (long, double) виртуальная машина выделяет два последовательных Slot-пространства с выравниванием высокого порядка, что эквивалентно разделению одного чтения и записи для типов данных long и double на два 32-битных чтения и записи.
- Спецификация виртуальной машины ссылочного типа не указывает ее длину, но в целом реализации виртуальных машин должны, по крайней мере, уметь находить индекс начального адреса объекта в куче Java и тип объекта в области методов прямо или косвенно из этого справочные данные.
- Слоты можно использовать повторно. Когда переменные в слоте выходят за пределы области действия, исходные данные будут перезаписаны при следующем выделении слота. Ссылки слотов на объекты повлияют на GC (если на них есть ссылки, они не будут собраны). Система не присваивает начальные значения локальным переменным (и переменным экземпляра, и переменным класса присваиваются начальные значения). То есть, нет такой фазы подготовки, как переменные класса.
- Система не присваивает начальные значения локальным переменным (и переменным экземпляра, и переменным класса присваиваются начальные значения). То есть, нет такой фазы подготовки, как переменные класса.
стек операндов
- Стек операндов совпадает с таблицей локальных переменных, а максимальная емкость таблицы локальных переменных, которую должен выделить метод, определяется во время компиляции.
- Каждый элемент стека операндов может иметь любой тип данных Java, включая long и double. Емкость стека, занимаемая 32-битными типами данных, равна 1, а емкость стека, занимаемая 64-битными типами данных, равна 2.
- Когда метод только начинает выполняться, рабочий случай этого метода пуст.В процессе выполнения будут различные инструкции байт-кода для записи и извлечения в стеке подсчета операторов, то есть в стеке/в операции стека (например, при выполнении арифметических операций оно выполняется посредством работы с числовым стеком или при вызове других методов передается через рабочий числовой стек).
- В концептуальной модели фреймы стека должны быть независимы друг от друга, но большинство виртуальных машин будут выполнять некоторую оптимизационную обработку, чтобы сделать таблицу локальных переменных и стек операндов частично перекрывающимися, так что при вызове метода вы можете напрямую использовать общие параметры, без необходимости делать дополнительное копирование параметров и прочую работу. Процесс перекрытия показан на рисунке:
динамическая ссылка
Каждая кадр стека содержит ссылку на метод, к которому рама стека принадлежит в бассейне постоянного времени выполнения. Существует большое количество символических ссылок в постоянном пуле классов. Инструкции по вызовам метода в Bytecode основаны на символах Из методов в постоянном пуле. Ссылаются как параметр. Некоторые из этих символических ссылок будут преобразованы в прямые ссылки (статические методы, частные методы и т. Д.) Во время этапа загрузки класса или когда они используются в первый раз. Это преобразование называется статическим разрешением, а другая часть будет преобразована На прямые ссылки во время каждого прогона. Эта часть называется динамической связью. Из-за ограниченного пространства мы не будем продолжать обсуждать процесс разборки и отправки здесь, и здесь нам нужно только знать разницу между статическим анализом и динамическим соединением.
адрес возврата метода
Когда метод начинает выполняться, толькоЕсть два способа выйти из этого метода:
- Механизм выполнения обнаруживает инструкцию байт-кода, возвращаемую любым методом: передается вызывающему методу верхнего уровня, есть ли возвращаемое значение, и тип возвращаемого значения будет определяться в соответствии с тем, какой метод он встречает для возврата инструкции.Этот метод выхода называется обычный Завершите экспорт.
- Исключение возникает во время выполнения метода: будь то исключение, сгенерированное внутри виртуальной машины Java, или исключение, сгенерированное thtrow в коде, если в таблице исключений этого метода не найден соответствующий обработчик исключений, это вызовет метод выхода.Метод выхода называется аварийным завершением выхода.Если метод выходит с использованием этого метода, он не возвращает никакого возвращаемого значения вызывающему объекту верхнего уровня. Независимо от того, какой способ вы используете для выхода из метода, вы должны вернуться в место, где метод был вызван, прежде чем программа сможет продолжить выполнение. Когда метод возвращается, некоторая информация может быть сохранена в кадре стека для восстановления состояния выполнения метода верхнего уровня. Когда общий метод завершается нормально, значение счетчика pc вызывающей стороны может быть использовано в качестве адреса возврата, и стек кадров, вероятно, сохранит значение этого счетчика в качестве адреса возврата. Процесс выхода из метода — это процесс извлечения фрейма стека из стека виртуальной машины, поэтому операции во время выхода могут включать: стек операндов Значение целочисленного счетчика pc указывает на инструкцию, следующую за вызовом этого метода.
Пример объяснения: Java код:
public class Test {
private static int add(int c){
return c + 10;
}
public static void main(String[] args) {
int a, b, c;
a = 1;
b = 2;
c = add(a*b);
c = c*(a+b);
}
}
Декомпилируется с помощью javap -v
Classfile /E:/Code/JAVA/JUC/out/production/JUC/net/ziruo/juc/Test.class
Last modified 2019-10-29; size 546 bytes
MD5 checksum 3526f85e07771be800502f7e10b50a3a
Compiled from "Test.java"
public class net.ziruo.juc.Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#24 // java/lang/Object."<init>":()V
#2 = Methodref #3.#25 // net/ziruo/juc/Test.add:(I)I
#3 = Class #26 // net/ziruo/juc/Test
#4 = Class #27 // java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 LocalVariableTable
#10 = Utf8 this
#11 = Utf8 Lnet/ziruo/juc/Test;
#12 = Utf8 add
#13 = Utf8 (I)I
#14 = Utf8 c
#15 = Utf8 I
#16 = Utf8 main
#17 = Utf8 ([Ljava/lang/String;)V
#18 = Utf8 args
#19 = Utf8 [Ljava/lang/String;
#20 = Utf8 a
#21 = Utf8 b
#22 = Utf8 SourceFile
#23 = Utf8 Test.java
#24 = NameAndType #5:#6 // "<init>":()V
#25 = NameAndType #12:#13 // add:(I)I
#26 = Utf8 net/ziruo/juc/Test
#27 = Utf8 java/lang/Object
{
public net.ziruo.juc.Test();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lnet/ziruo/juc/Test;
private static int add(int);
descriptor: (I)I
flags: ACC_PRIVATE, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: iload_0
1: bipush 10
3: iadd
4: ireturn
LineNumberTable:
line 12: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 c I
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=4, args_size=1
0: iconst_1
1: istore_1
2: iconst_2
3: istore_2
4: iload_1
5: iload_2
6: imul
7: invokestatic #2 // Method add:(I)I
10: istore_3
11: iload_3
12: iload_1
13: iload_2
14: iadd
15: imul
16: istore_3
17: return
LineNumberTable:
line 18: 0
line 19: 2
line 20: 4
line 21: 11
line 22: 17
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 args [Ljava/lang/String;
2 16 1 a I
4 14 2 b I
11 7 3 c I
}
Объяснение основных комментариев кода:
0: iconst_1 (把1压入操作数栈栈顶)
1: istore_1 (把操作数栈栈顶的出栈放入局部变量表索引为1的位置)
2: iconst_2 (把2压入操作数栈栈顶)
3: istore_2 (把操作数栈栈顶的出栈放入局部变量表索引为2的位置)
4: iload_1 (把局部变量表索引为1的值放入操作数栈栈顶)
5: iload_2 (把局部变量表索引为2的值放入操作数栈栈顶)
6: imul (把操作数栈栈顶的和栈顶下面的一个进行乘法运算后放入栈顶)
7: invokestatic #2 // Method add:(I)I (执行静态方法,返回的值放入操作数栈)
10: istore_3 (把操作数栈栈顶的出栈放入局部变量表索引为3的位置)
11: iload_3 把局部变量表索引为3的值放入操作数栈栈顶)
12: iload_1 把局部变量表索引为1的值放入操作数栈栈顶)
13: iload_2 把局部变量表索引为2的值放入操作数栈栈顶)
14: iadd (把操作数栈栈顶的和栈顶下面的一个进行加法运算后放入栈顶)
15: imul (把操作数栈栈顶的和栈顶下面的一个进行乘法运算后放入栈顶)
16: istore_3 (把操作数栈栈顶的出栈放入局部变量表索引为3的位置)
17: return (结束)
Справочная статья: