Подтвердить что ты не робот

Нажатие переменных в стек и переменные, живущие в разности стеков?

Итак, я знаю, что существует 2 области памяти: Стек и Куча.

Я также знаю, что если вы создадите локальную переменную, она будет жить в стеке, а не в куче. Стек будет расти по мере ввода данных в него, как в:

enter image description here

Теперь я попытаюсь передать путаницу, которую я вам даю:

Например, этот простой код Java:

public class TestClass {
    public static void main(String[] args)  {
        Object foo = null;
        Object bar = null;
    }
}

преобразуется в этот байтовый код:

public static void main(java.lang.String[]);
  Code:
   Stack=1, Locals=3, Args_size=1
   0:   aconst_null
   1:   astore_1
   2:   aconst_null
   3:   astore_2
   4:   return

LineNumberTable: 
line 5: 0
line 6: 2
line 7: 4

LocalVariableTable: 
Start  Length  Slot  Name   Signature
0      5      0    args       [Ljava/lang/String;
2      3      1    foo       Ljava/lang/Object;
4      1      2    bar       Ljava/lang/Object;

где по определению acons_null:

push a null reference onto the stack

и astore_1:

store a reference into local variable 1

Смятение, которое я испытываю, это то, что мы вложили foo в стек, и мы снова сохранили его в стеке? Что означает сохранение ссылки в локальной переменной? Где живет эта локальная переменная? В том же стеке мы ввели foo или эти отдельные стеки?

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

4b9b3361

Ответ 1

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

В рамке стека есть две области:

  • стека операндов (не путайте слово "стоп" здесь с самим стекем JVM - стек здесь обозначает область как структуру "последний в первом" ).
  • Массив локальных переменных, где каждая переменная имеет индекс (начиная с нуля).

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

Как объяснено в описании aconst_null, команда aconst_null нажимает ссылку на объект null на стек .

И как объяснено в описании astore_<n> (где n может быть 0, 1, 2 или 3):

<n> должен быть индексом в локальном массиве переменных текущего кадра (п. 2.6). objectref в верхней части стека операндов должен иметь тип returnAddress или тип reference. Он выставляется из стека операндов, а значение локальной переменной в <n> равно objectref.

Итак, в вашем примере оператор Object foo = null переводит на следующее:

  • Нажмите null (специальная ссылка, которая указывает на "ничего" ) на верхнюю часть стека операндов.
  operand stack
   __________
  |   null   | <-- null is pushed on the operand stack
  |__________|
  |          |
  |__________|
  |          |
  |__________|
  1. Поставьте ссылку из стека операндов и сохраните ее в локальной переменной в индексе 1. Эта локальная переменная соответствует foo.
  operand stack                           local variables
   __________      _______________ _______________ _______________ _______________
  |          |    |      args     |   foo (null)  |               |               |
  |__________|    |_______0_______|_______1_______|_______2_______|_______3_______|
  |          |                    store null in LV#1 
  |__________|
  |          |
  |__________|

Те же шаги выполняются для Object bar = null, за исключением того, что null хранится в локальной переменной в индексе 2.

Источник: спецификация виртуальной машины Java (см. этот раздел).

Ответ 2

Вы должны посмотреть на структуру структуры стека Java.

Кадр java stack содержит 3 вещи:

  • Локальная таблица переменных
  • Стек операнда
  • Ссылка на постоянный пул классов AKA Frame Data​​li >

Итак, push a null reference onto the stack → подталкивает ссылку на стек операнда.

store a reference into local variable 1 → сохраняет ссылку в слот 1 таблицы локальных переменных

Ответ 3

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

Если вы хотите что-либо делать с любыми переменными (локальные переменные, статические переменные или нестатические переменные), вы делаете это через стек операнда. Инструкции Java Bytecode работают в основном только с стеком операндов.

Например,

  • foo = bar будет соответствовать aload_2 и astore_1, что просто означает, что значение локальной переменной 2 на стеке операндов и поместить все поверх стека операндов на локальную переменную 1
  • if (foo == null) ... будет соответствовать aload_1 и ifnonnull 5, где последний сообщает JVM: если что-то поверх стека операндов не равно null, переходите к следующим 5 смещениям команды; в противном случае переходите к следующей инструкции.
  • int x = args.length будет соответствовать aload_0, arraylength, istore_3, что означает локальную переменную 0, поместить массив поверх стека операндов и вытолкнуть его длину назад, поместить целое число и сохранить его в локальном переменная 3
  • Численные операции, такие как iadd, isub, imul, idiv выставляют два целочисленных значения из стека операндов и возвращают результат
  • При вызове метода стек операнда вызывается и передается в качестве аргументов локальным переменным нового метода.
  • putstatic/getstatic вызывает/ставит/статические переменные
  • putfield/getfield всплывает/толкает/нестатические переменные

Ответ 4

Это тот же самый стек.

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

В простом jvm

При вызове метода он резервирует пространство для локальных переменных в стеке. Он в основном увеличивает указатель стека на открытое пространство для него локальных переменных. Родительский объект метода (если метод экземпляра) и аргументы метода являются первыми локалями.

Чтобы назначить что-то из стека локальному var, нужно скопировать из верхней части стека в соседний адрес, несколько позиций до, в той же области памяти.

Во время astore 1 в вашем примере:

locals/stack
[local 0] // args
[local 1] // foo   <--+
[local 2] // bar      |
..return address..    |
[stack 0] // null  ---+