Ответ
В Java байт-код методов хранится в области памяти JVM, называемой Metaspace (до Java 8 — PermGen).
Что хранится в Metaspace:
- Байт-код всех загруженных классов (включая методы).
- Метаданные классов (имена, модификаторы, информация о полях и методах).
- Константы времени компиляции.
- Важно: Сами выполняемые инструкции метода (байт-код) хранятся здесь, но данные для их выполнения (локальные переменные, параметры) — в стеке потока.
Ключевые особенности Metaspace:
- Не-куча (Non-Heap): Отделена от основной кучи (Heap).
- Динамический размер: В отличие от PermGen, Metaspace по умолчанию автоматически увеличивается в пределах доступной native-памяти ОС.
- Общая для всех потоков.
Пример и визуализация:
class Calculator {
// Статическая переменная хранится в Metaspace (в структуре класса)
static String OPERATOR = "+";
// Байт-код этого метода хранится в Metaspace
int add(int a, int b) {
int result = a + b; // Локальные переменные a, b, result хранятся в стеке потока
return result;
}
}
Схема памяти JVM (упрощенно):
- Heap: Объекты, массивы.
- Metaspace: Классы, байт-код методов, статические поля.
- Stack: Локальные переменные и вызовы методов.
Ответ 18+ 🔞
Давай разберём эту тему, чтобы не было, как у Герасима, — молчал, молчал, а потом «Му-му» и всё, нихуя не понятно.
Представь себе, что JVM — это такой огромный, блядь, театр. А каждый класс в твоей программе — это пьеса. Так вот, Metaspace — это, сука, архив, где лежат все тексты этих пьес, то есть байт-код твоих методов. До Java 8 этот архив назывался PermGen и был, как шкаф в хрущёвке, — маленький и тесный, постоянно всё не влезало. А сейчас Metaspace — это уже целый склад, который может расширяться, пока оперативка не кончится, ёпта.
Что конкретно там валяется:
- Сам байт-код всех методов, которые ты написал и которые загрузились.
- Всякая служебная хуйня про классы: их имена, кто их родители, какие у них поля и методы.
- Константы, которые были известны ещё при компиляции.
Но! Запомни раз и навсегда, как «Муму»: байт-код метода лежит в Metaspace, а вот данные для его работы — локальные переменные, аргументы, адреса возврата — это уже в стеке потока. Это две абсолютно разные области, блядь. Не путай, а то получится, как в той истории: «Кто серит на крыше? — Муму!». Полная ерунда.
Особенности Metaspace, чтобы блеснуть умом:
- Не-куча (Non-Heap): Это не та куча, где объекты живут. Это отдельная, блядь, территория.
- Растёт как на дрожжах: В отличие от старого PermGen, который надо было вручную раздувать, Metaspace сама расширяется, пока система не скажет «ну нахуй, всё, память кончилась».
- Общая для всех: Все потоки в приложении смотрят в один и тот же архив с пьесами. Иначе был бы пиздец, каждый бы свою версию класса таскал.
Смотри, как это выглядит в коде:
class Calculator {
// Эта статическая переменная — она тоже в Metaspace, в описании класса.
static String OPERATOR = "+";
// А вот байт-код ЭТОГО метода — он тоже в Metaspace, как инструкция.
int add(int a, int b) {
int result = a + b; // А вот a, b и result — это уже в стеке потока, когда метод выполняется!
return result;
}
}
Итоговая, блядь, схема на пальцах:
- Heap (Куча): Тут живут объекты (
new Calculator()) и массивы. Беспорядочная, шумная жизнь, сборщик мусора постоянно убирается. - Metaspace: Тихий архив. Лежат «чертежи» классов (байт-код) и статика.
- Stack (Стек потока): Активная работа. Здесь методы вызываются, локальные переменные создаются и умирают. Своя зона у каждого потока.
Вот и вся магия. Главное — не делать, как тот максималист Герасим, и не пытаться всё свалить в одну кучу. Всё должно быть на своих местах: код — в Metaspace, данные — в стеке и куче. Тогда и работать будет, и память не кончится раньше времени.