Об управлении памятью в Java и C++

Что ж, мне дали задание в основном выяснить, как работает распределение памяти для любого языка, который я буду использовать. После некоторого исследования у меня есть несколько вопросов и сомнений, в которых я хотел бы разобраться. Например:

Я прочитал здесь, что Java точно определяет, как организовано содержимое стека. Глядя на Структура спецификации JVM, он в основном говорит, что стек содержит фреймы, и что фреймы содержат все, что находится внутри класса, путем правильного распределения переменных и функций. Возможно, мне что-то здесь не хватает, но я не понимаю, чем это отличается от того, что делает C++. Я спрашиваю, потому что первая ссылка говорит, что спецификация Java для содержимого стека избегает несовместимости компиляторов.

Кроме того, мне еще предстоит выяснить, как сегменты памяти точно организованы друг над другом. Например, я знаю, что память разделена на глобальные переменные, стек вызовов, кучу и код для C++, но я не знаю, выше ли адрес кучи, чем у стека, или это зависит от реализации. Я также задаюсь вопросом, есть ли в программе на Java что-то большее, и как бы это было оформлено. Я полагаю, что существует стандарт, поскольку JVM должна знать, где все это использовать, хотя я полагаю, что у нее могут быть просто указатели, а все остальное оставить ОС. Я тоже полагаю, что должен быть хотя бы стандарт де-факто.

Еще одна вещь, которую я не понимаю, - это пул констант времени выполнения. Это должно быть «представление таблицы constant_pool в файле класса для каждого класса или интерфейса во время выполнения», но я не думаю, что понимаю, что он делает. Кажется, есть тег, указывающий, к какому типу относится рассматриваемая структура? Затем имя структуры (заданное программистом или присвоенное базовой системой?) Тогда кажется, что остальное зависит от того, что описывает тег (поток, массив и т. д.).

Если моя интерпретация пула констант времени выполнения верна, то зачем они нужны, как и кадры стека? Это потому, что кадры стека заботятся только о сегментах стека, а пул констант времени выполнения также должен иметь указатели на выделенную кучей память?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
9
0
9 045
2

Ответы 2

Какую именно задачу вам дали?

Основное различие между Java и C++ заключается в том, что Java собирает мусор виртуальной машиной, тогда как в C++ программа выполняется непосредственно на машине, а управление памятью осуществляется через службы ОС.

Что касается стека, фрейм - это просто более «официальная» и стандартная форма того, что делают компиляторы C++. Компиляторы C++ просто кладут элементы друг на друга в стек при переходе от вызова к вызову. В Java термин - фрейм, и поскольку скомпилированный код Java должен работать на любой платформе, существуют очень четкие стандарты того, как это происходит. В C++ каждый компилятор может обрабатывать стек по-разному (например, даже по природе размера слова).

В Java все работает в виртуальной машине, которая всем управляет, хотя кое-что делегирует среде. Другими словами, у вас нет доступа к тому, куда JVM помещает ваши данные и ваш код, и ваш код может никогда даже не стать настоящим «сегментом кода». Другими словами, на это невозможно ответить. В C++ все работает на оборудовании, поэтому у вас будут сегменты стека, сегменты данных и т. д. Посмотрите информацию о C++.

В C++ классы не имеют представления в памяти во время выполнения; Фактически, вы можете скомпилировать C++ в C, а затем скомпилировать результаты в сборку. В Java все также представлено во время выполнения, поэтому вы можете спросить объект, к какому классу он принадлежит и какой метод поддерживает. Следовательно, каждый файл класса имеет «пул констант», в котором появляются строки, представляющие такие вещи, как имена методов, имена полей и т. д. Фактическое определение класса относится к пулу. Другими словами, это не имеет ничего общего с фреймами стека. Фреймы стека - это место, где хранятся параметры метода, локальные переменные и возвращаемые значения.

Последняя часть о классах C++, не имеющих представления в памяти, не совсем верна. C++ поддерживает RTTI, который необходим для некоторых вещей (например, dynamic_cast, typeid и обработки исключений).

Kevin Loney 14.01.2009 03:27

Я согласен. Однако это было в пределах моего ответа относительно постоянного пула. AFAIK, RTTI в C++ не сохраняет наименования исходных материалов.

Uri 14.01.2009 04:26

Не совсем верно, рассмотрите typeid (x) .name (), даже если имя искажено (что обратимо), это все равно исходный материал.

Kevin Loney 14.01.2009 05:02

Looking at the JVM spec structure, it basically says the stack contains frames, and that the frames contain whatever is inside the class by properly allocating the variables and functions. Maybe I am missing something here, but I don't understand how this is any different than what C++ does. I ask because the first link says Java's specification of stack contents avoid compiler incompatibilities.

На практике компиляторы C++ следуют той же базовой стратегии. Однако комитет по стандартам не считает это языковым вопросом. Вместо этого компиляторы C++ следуют этой системе, потому что так устроено большинство процессоров и операционных систем. Различные платформы расходятся во мнениях относительно того, передаются ли данные в функции в стеке или через регистры (RISC-машины), растет ли стек вверх или вниз, существуют ли разные соглашения о вызовах, позволяющие «нормальным» вызовам использовать стек, а другим - использовать что-то. иначе (например, __fastcall и голый), есть ли такие вещи, как вложенные функции, поддержка хвостового вызова и т. д.

Фактически, соответствующий компилятор C++ может скомпилировать что-то вроде Scheme VM, где «стек» сильно отличается, потому что Scheme требует, чтобы реализации поддерживали как хвостовые вызовы, так и продолжения. Я никогда не видел ничего подобного, но это было бы законно.

«Несовместимость компилятора» наиболее очевидна, если вы попытаетесь написать сборщик мусора.:

all local variables, both for the current function and all its callers, are in ["the" stack, but consider ucontext.h and Windows Fibers]. For each platform (meaning, OS + CPU + compiler) there's a way to find out where ["the" stack] is. Tamarin does that, then it scans all that memory during GC to see where the locals point to. ...

This magic lives in a macro, MMGC_GET_STACK_EXTENTS, defined in the header MMgc/GC.h. ... [T]here’s a separate implementation for each platform.

At any given moment, some locals might be in CPU registers and not on the stack. To cope with this, the macro uses a few lines of assembly code to dump the contents of all the registers onto the stack. That way MMgc can just scan the stack and it’ll see all local variables.


Кроме того, объекты в Java обычно не размещается в стеке. Вместо этого ссылки на них есть. ints, double, boolean и другие примитивные типы выделяются в стеке. В C++ все может быть размещено в стеке, у которого есть свой список плюсов и минусов.

Another the thing I don't understand is the runtime constant pool. It's supposed to be "a per-class or per-interface runtime representation of the constant_pool table in a class file", but I don't think I understand what it does.

Рассмотреть возможность:

String s = "Hello World";
int i = "Hello World".length();
int j = 5;

s, i и j - все переменные, и каждая из них может быть изменена позже в программе. Однако «Hello World» - это объект типа String, который нельзя изменить, 5 - это целое число, которое нельзя изменить, а «Hello World» .length () может быть определено во время компиляции, чтобы всегда возвращать 11. Эти константы являются для них могут быть вызваны действительные объекты и методы (ну, по крайней мере, для String), поэтому их нужно где-то разместить. Но их нельзя изменить никогда. Если эти константы принадлежат классу, они выделяются в пуле констант для каждого класса. Другие постоянные данные, которые не являются частью класса (например, идентификатор потока main ()), выделяются в пуле констант для каждой среды выполнения («среда выполнения» в данном случае означает «экземпляр JVM»).

В стандарте C++ есть некоторые формулировки подобной техники, но реализация оставлена ​​на усмотрение двоичного формата (ELF, a.out, COFF, PE и т. д.). Стандарт ожидает, что константы, которые являются интегральными типами данных (bool, int, long и т. д.) Или строки в стиле c, будут фактически храниться в постоянной части двоичного файла, в то время как другие постоянные данные (double, float, классы) могут быть сохранены в качестве переменной вместе с флагом, говорящим о том, что «переменная» не может быть изменена (также допустимо хранить их с целочисленными строковыми константами и строковыми константами в стиле c, но во многих двоичных форматах это не вариант).

Вообще говоря, «секция постоянных данных» двоичного файла может использоваться совместно, когда одновременно открыто более одной копии программы (поскольку постоянные данные будут идентичны в каждой копии программы). В ELF этот раздел называется разделом .rodata..

Хорошая рецензия. Небольшая поправка: хотя обычно объекты не выделяются в стеке, поскольку Java SE 6 javac может выполнять анализ выхода, он может даже выделять объекты в стеке. См. ibm.com/developerworks/java/library/j-jtp09275.html. Но в любом случае это должно быть прозрачно для разработчиков :-).

sleske 14.05.2009 13:51

Другие вопросы по теме