Где Строковой константы в Java моря, в куче или в стеке?
Я знаю, понятие константы бассейн и строковая константа бассейн используют виртуальные машины для обработки строковых литералов. Но я не знаю, какой тип памяти используется на JVM для хранения строковых констант. Стек или куча? Поскольку его литерал, который не связан ни с одним экземпляром, я бы предположил, что он будет храниться в стеке. Но если он не упоминается каким-либо экземпляром, литерал должен быть собран GC run (исправьте меня, если я ошибаюсь), так как это обрабатывается, если он хранится в стек?
6 ответов:
ответ технически ни один. Согласно спецификации виртуальной машины Java, область для хранения строковых литералов находится в пул констант времени выполнения. Область памяти пула констант времени выполнения выделяется на основе каждого класса или интерфейса, поэтому она вообще не привязана ни к каким экземплярам объектов. Пул констант времени выполнения является подмножеством зона метод который " хранит структуры для каждого класса, такие как пул констант времени выполнения, данные полей и методов, а также код для методов и конструкторов, включая специальные методы, используемые в инициализации класса и экземпляра и инициализации типа интерфейса". Спецификация VM говорит, что хотя зона метод логически является частью кучи, он не диктует, что память, выделенная в области метода, подлежит сборке мусора или другим поведениям, которые были бы связаны с обычными структурами данных, выделенными для кучи.
Как пояснил ответ, точное расположение пула строк не указано и может варьироваться от одной реализации JVM к другой.
интересно отметить, что до Java 7 пул находился в пространстве permgen кучи на hotspot JVM, но он был перемещен в основную часть кучи с Java 7:
площадью: HotSpot
справка: в JDK 7 интернированные строки отсутствуют дольше выделяется в постоянной генерации кучи Java, но вместо этого выделяются в основной части кучи Java (известный как молодые и старые поколения), наряду с другими объектами, созданными приложением. Это изменение приведет к большему количеству данных, находящихся в основной куче Java, и меньшему количеству данных в постоянном поколении, и таким образом может потребовать изменения размеров кучи. Большинство приложений видят только относительно небольшие различия в использовании кучи из-за этого изменения, но большие приложения, которые загружают много классов или интенсивно используют строку.метод intern () будет видеть более существенные различия. RFE: 6962931и в Java 8 Hotspot, постоянное поколение было полностью удалено.
строковые литералы хранятся в стеке.
строковые литералы (или, точнее, строковые объекты, которые представляют их)
areисторически хранились в куче, называемой кучей "пермген". (Permgen является коротким для постоянного поколения.)при нормальных обстоятельствах строковые литералы и многое другое в куче permgen "постоянно" доступны и не собираются в мусор. (Например, строковые литералы всегда доступны из объектов кода, которые их используют.) Однако вы можете настроить JVM для поиска и сбора динамически загруженных классов, которые больше не нужны, и это может привести к тому, что строковые литералы будут собраны в мусор.
уточнение #1 - Я не говорю, что Permgen не получает GC'Ed. Это происходит, как правило, когда JVM решает запустить полный GC. Я хочу сказать, что строка литералы будет доступен до тех пор, пока код, который их использует, доступен, и код будет доступен до тех пор, пока доступен загрузчик классов кода, а для загрузчиков классов по умолчанию это означает "навсегда".
уточнение #2 - на самом деле, Java 7 хранит интернированные строковые объекты в обычной куче. Это включает в себя (я предполагаю) строковый объект, представляющий строковые литералы. (Подробнее см. ответ @ assylias.)
группировка строк
объединение строк (иногда также называемое канонизацией строк) является процесс замены нескольких строковых объектов с равным значением, но другой идентификатор с одним общим строковым объектом. Вы можете достигнуть эта цель путем держать вашу собственную карту (с по возможности мягким или слабые ссылки в зависимости от ваших требований) и использование карты значения как канонизированные значения. Или вы можете использовать строку.интерн() метод который предоставляется вы по JDK.
во время Java 6 с помощью строки.интерн() был запрещен многими стандарты из-за высокой возможности получить исключение OutOfMemoryException, если объединение вышло из-под контроля. Oracle Java 7 реализация строки объединение было значительно изменено. Вы можете посмотреть детали внутри http://bugs.sun.com/view_bug.do?bug_id=6962931 и http://bugs.sun.com/view_bug.do?bug_id=6962930.
строку.интерн() в Java 6
в те старые добрые времена все интернированные строки хранились в PermGen – фиксированный размер части кучи в основном используется для хранения загруженных классов и струнный пул. Кроме явно интернированных строк, строка PermGen пул также содержит все литеральные строки, ранее используемые в вашей программе (здесь используется важное слово-если класс или метод никогда не был loaded / called, любые константы, определенные в нем, не будут загружены).
самая большая проблема с таким строковым пулом в Java 6 было его расположение – в PermGen. PermGen имеет фиксированный размер и не может быть расширен по во время выполнения. Вы можете установить его с помощью опции-XX:MaxPermSize=96m. Насколько мне известно знайте, размер PermGen значения по умолчанию меняет между 32M и 96M в зависимости от платформа. Вы можете увеличить его размер, но его размер все равно будет зафиксированный. Такое ограничение требовало очень осторожного использования строки.интерн – вам лучше не интернировать какой-либо неконтролируемый пользовательский ввод с помощью этого метода. Вот почему строка объединение во время Java 6 было в основном реализовано в карты, управляемые вручную.
строку.стажер() в Java 7
инженеры Oracle внесли чрезвычайно важное изменение в строку логика объединения в Java 7-пул строк был перемещен в кучу. Это означает, что вы больше не ограничены отдельным фиксированным размером область памяти. Все строки находятся в куче, как и большинство других обычные предметы, что позволяет управление только размером кучи в то время как настройка вашего приложения. Технически, это само по себе может быть достаточным причина пересмотреть использование строки.intern () в ваших программах Java 7. Но есть и другие причины.
строковые значения пула являются собранным мусором
Да, все строки в пуле строк JVM имеют право на мусор коллекция, если нет ссылок на них из корней вашей программы. Это относится ко всем обсуждаемым версиям Ява. Это означает, что если ваш интернированная строка вышла из области видимости и других ссылок на нее нет это-это будет мусор, собранный из пула строк JVM.
имея право на сбор мусора и проживая в куче, JVM струнный пул кажется правильным местом для всех ваших строк, не так ли? Теоретически это верно – неиспользуемые строки будут собираться из мусора пул, используемые строки позволят вам сохранить память в случае, если тогда вы получить равную строку из вход. Кажется, это идеальная память стратегия экономии? Почти так. Вы должны знать, как строковый пул осуществлены до принятия каких-либо решений.
к великим ответам, которые уже включены здесь, я хочу добавить что - то, чего не хватает в моей перспективе-и иллюстрации.
как вы уже JVM делит выделенную память для программы Java на две части. один из них стек и кучу. Стек используется для целей выполнения, а куча-для целей хранения. В этой памяти кучи JVM выделяет некоторую память, специально предназначенную для строковых литералов. Эта часть памяти кучи называется строковые константы бассейн.
так например, если вы инициализируете следующие объекты:
String s1 = "abc"; String s2 = "123"; String obj1 = new String("abc"); String obj2 = new String("def"); String obj3 = new String("456);строковые литералы
s1иs2перейдет в пул строковых констант, объекты obj1, obj2, obj3 в кучу. Все они будут ссылаться на стек.кроме того, обратите внимание, что "abc" появится в куче и в пуле констант строк. Почему это
String s1 = "abc"иString obj1 = new String("abc")будет создан таким образом? Это потому чтоString obj1 = new String("abc")явно создает новый и совершенно distinct экземпляр объекта StringString s1 = "abc"может повторно использовать экземпляр из пула строковых констант, если он доступен. Для более подробного объяснения:https://stackoverflow.com/a/3298542/2811258
Как объясняют другие ответы память в Java делится на две части
1. Стек: один стек создается в потоке, и он хранит кадры стека, которые снова хранят локальные переменные, и если переменная является ссылочным типом, то эта переменная ссылается на ячейку памяти в куче для фактического объекта.
2. Куча: все виды объектов будут созданы только в куче.
динамическая память снова разделена на 3 порции
1. Молодое Поколение: хранит объекты, которые имеют короткий срок службы, само молодое поколение можно разделить на две категории Иден Пробел и Survivor Space.
2. Старое Поколение: хранить объекты, которые пережили много циклов сборки мусора и все еще ссылаются.
3. Постоянное Поколение: хранит метаданные о программе, например, во время выполнения постоянно бассейн.
пул строковых констант относится к области постоянной генерации памяти кучи.
Как говорится в как JVM обрабатывает метод перегрузки и переопределения внутри, мы можем видеть пул констант времени выполнения для нашего кода в байт-коде с помощью
javap -verbose class_nameкоторый покажет нам ссылки на методы (#Methodref ), объекты класса ( #Class), строковые литералы ( #String)


Comments