Как Java хранит примитивные типы в ОЗУ? [дубликат]
этот вопрос уже есть ответ здесь:
- примитивы Java идут в стек или кучу? 5 ответов
речь идет не о том, идут ли примитивы в стек или кучу, а о том, где они сохраняются в фактической физической ОЗУ.
взять простой пример:
int a = 5;
Я знаю 5 хранится в блоке памяти.
моя область интересов-где хранится переменная "a"?
связанные с этим дополнительные вопросы: где это происходит, когда "a" связывается с блоком памяти, который содержит примитивное значение 5? Есть ли другой блок памяти, созданный для хранения "a"? Но это будет выглядеть так, как будто a является указателем на объект, но это примитивный тип, участвующий здесь.
2 ответов
подробно примитивы Java идут в стек или кучу? -
допустим у вас есть функция foo()
:
void foo() {
int a = 5;
system.out.println(a);
}
затем, когда компилятор компилирует эту функцию, он создаст инструкции байт-кода, которые оставляют 4 байта места в стеке всякий раз, когда эта функция вызывается. Имя "a" полезно только вам-компилятору, он просто создает для него место, запоминает, где это место находится, и везде, где он хочет использовать значение вместо этого он вставляет ссылки на место памяти, зарезервированное для этого значения.
если вы не знаете, как работает стек, он работает следующим образом: каждая программа имеет по крайней мере один поток, и каждый поток имеет ровно один стек. Стек представляет собой непрерывный блок памяти (который также может расти при необходимости). Первоначально стек пуст, пока не будет вызвана первая функция в вашей программе. Затем, когда вызывается ваша функция, ваша функция выделяет место в стеке для себя, для все его локальные переменные, для его возвращаемых типов и т. д.
когда функция main
вызов другой функции foo
, вот один пример того, что может произойти (здесь есть пара упрощающих белых лжи):
-
main
хочет передать параметрыfoo
. Он выталкивает эти значения в верхнюю часть стека таким образом, чтоfoo
будет точно знать, где они будут помещены (main
иfoo
передаст параметры в последовательном путь.) -
main
нажимает адрес, куда должно вернуться выполнение программы послеfoo
сделано. Это увеличивает указатель стека. -
main
звонкиfoo
. - , когда
foo
запускается, он видит, что стек в настоящее время находится по адресу X -
foo
хочет выделить 3int
переменные в стеке, поэтому ему нужно 12 байтов. -
foo
будет использовать X + 0 для первого int, X + 4 для второго int, X + 8 для третий.- компилятор может вычислить это во время компиляции, и компилятор может полагаться на значение регистра указателя стека (ESP в системе x86), и поэтому код сборки, который он записывает, делает такие вещи, как "хранить 0 в адресе ESP + 0", "хранить 1 в адресе ESP + 4" и т. д.
- параметры
main
нажал на стеке перед вызовомfoo
и поfoo
путем вычисления некоторого смещения от стека указатель.-
foo
знает, сколько параметров он принимает (скажем, 3), поэтому он знает, что, скажем, X - 8 - первый, X - 12-второй, а X-16-третий.
-
- теперь
foo
имеет место в стеке, чтобы сделать свою работу, он делает это и заканчивает - перед
main
под названиемfoo
,main
написал свой обратный адрес в стеке перед увеличением указателя стека. -
foo
ищет адрес чтобы вернуться к-скажем, что адрес хранится вESP - 4
-foo
смотрит на это место в стеке, находит там обратный адрес и переходит к обратному адресу. - теперь остальная часть кода в
main
продолжает работать, и мы сделали полную поездку туда и обратно.
обратите внимание, что каждый раз, когда вызывается функция, она может делать все, что захочет, с памятью, на которую указывает текущий указатель стека и все после него. Каждый раз, когда функция освобождает место в стеке для само собой, это увеличивает указатель стека перед вызовом других функций, чтобы убедиться, что все знают, где они могут использовать стек для себя.
я знаю, что это объяснение немного размывает линию между x86 и java, но я надеюсь, что это поможет проиллюстрировать, как на самом деле работает оборудование.
теперь это охватывает только "стек". Стек существует для каждого потока в программе и фиксирует состояние цепочки вызовов функций между каждой функции работает на этой нити. Впрочем, программа может иметь несколько потоков, и каждый поток имеет свой независимый стек.
что происходит, когда два вызова функций хотят иметь дело с одним и тем же фрагментом памяти, независимо от того, в каком потоке они находятся или где они находятся в стеке?
вот где приходит куча. Обычно (но не всегда) одна программа имеет ровно одну кучу. Куча называется кучей, потому что это просто большая куча памяти.
использовать память в куче, вы должны вызвать процедуры распределения-процедуры, которые находят неиспользуемое пространство и дают его вам, и процедуры, которые позволяют вам вернуть пространство, которое вы выделили, но больше не используете. Распределитель памяти получает большие страницы памяти из операционной системы, а затем раздает отдельные маленькие биты тому, что ему нужно. Он отслеживает, что ОС дала ему, и из этого, что она дала остальной части программы. Когда программа запрашивает память кучи, она ищет самый маленький кусочек памяти, который у него есть, который соответствует потребностям, помечает этот кусок как выделяемый и передает его обратно остальной части программы. Если у него больше нет свободных кусков, он может попросить операционную систему больше страниц памяти и выделить оттуда (до некоторого предела).
в таких языках, как C, те процедуры выделения памяти, которые я упомянул, обычно называются malloc()
попросить памяти и free()
, чтобы вернуть его.
Java с другой стороны у hand нет явного управления памятью, как у C, вместо этого у него есть сборщик мусора - вы выделяете любую память, которую хотите, а затем, когда вы закончите, вы просто прекратите ее использовать. Среда выполнения Java будет отслеживать, какую память вы выделили, и будет сканировать вашу программу, чтобы узнать, не используете ли вы все свои выделения больше и автоматически освобождаете эти куски.
Итак, теперь мы знаем, что память выделяется в куче или в стеке, что происходит, когда я создаю закрытую переменную в классе?
public class Test {
private int balance;
...
}
откуда берется это воспоминание? Ответ-куча. У вас есть код, который создает новый
я думаю, я понял, что вы не хотите спрашивать, хранятся ли данные в куче или стеке! у нас одна и та же загадка!
вопрос, который вы задали, очень связан с языком программирования и тем, как операционная система имеет дело с процессом и переменными.
это очень интересно, потому что, когда я был в своем университете, изучая C и c++, я сталкиваюсь с тем же вопросом, что и вы. после прочтения некоторых ASM
код, составленный GCC
, у меня есть немного о понимании с этим, давайте обсудим об этом, если какая-либо проблема, прокомментируйте ее и позвольте мне узнать больше об этом.
на мой взгляд, имя переменной не будет сохранено, а значение переменной будет сохранено, потому что в ASM
код, нет реального variable name
за исключением cache name
короче говоря, вся так называемая переменная - это просто off set
С stack
или heap
.
что, я думаю, является подсказкой для моего обучения, так как ASM
интернет-с имени переменной, другие язык может иметь ту же стратегию.
Они просто хранят off set
для реального места для хранения данных.
приведем пример, скажем переменную name a
расположенный по адресу @1000
типа этого a
является целым числом, таким образом, в памяти address
addr type value
@1000 int 5
что @1000-это off set
где хранятся реальные данные.
как вы можете видеть, что данные помещаются в реальном off set
для этого.
В моем понимании процесса, что все переменная будет заменена на " адрес "этой" переменной "в начале процесса, что означает, что в то время как CPU имеет дело только с" адресом", который уже выделен в памяти.
давайте еще раз рассмотрим эту процедуру: что вы определилиint a=5; print(a);
после компиляции программа переносится в другой формат (все по моему воображению):
stack:0-4 int 5
print stack:0-4
в то время как в ситуации процесса, который реально выполняется, я думаю, что память будет такой:
@2000 4 5 //allocate 4 byte from @2000, and put 5 into it
print @2000 4 //read 4 byte from @2000, then print
поскольку память процесса выделяется CPU,@2000
это off set
этого имени переменной, что означает name
будет заменен только адресом памяти, затем будет читать данные 5 с этого адреса, а затем выполнить команду печати.
переосмысливать
после завершения моего письма, я обнаружил, что это довольно трудно представить другими людьми, мы можем обсудить его, если какие-либо проблемы или ошибки я сделал.