Gdzie żyje Pula ciągów Javy, sterta czy stos?

Znam pojęcie puli stałych i puli ciągów ciągów używanych przez JVMs do obsługi liter ciągów. Ale nie wiem, jaki typ pamięci jest używany przez JVM do przechowywania ciągów stałych literałów. Sterta czy sterta? Ponieważ jest to literał, który nie jest powiązany z żadną instancją, zakładam, że będzie przechowywany w stosie. Ale jeśli nie jest on odwołany przez żadną instancję, literał musi być pobrany przez GC run( popraw mnie, jeśli się mylę), więc jak to jest obsługiwane, jeśli to jest przechowywany w stosie?

Author: dimo414, 2011-02-07

6 answers

Odpowiedź jest technicznie Żadna. Zgodnie ze specyfikacją Java Virtual Machine obszar do przechowywania literałów łańcuchowych znajduje się w stałej puli . Obszar pamięci stałej puli uruchomieniowej jest przydzielany na podstawie klas lub interfejsów, więc nie jest powiązany z żadnymi instancjami obiektu. Stała Pula runtime jest podzbiorem obszaru metody , który " przechowuje struktury poszczególnych klas, takie jak stała Pula runtime, dane pól i metod oraz kod dla metody i konstruktory, w tym specjalne metody używane w inicjalizacji klas I instancji oraz inicjalizacji typu interfejsu". Specyfikacja maszyny wirtualnej mówi, że chociaż obszar metody jest logicznie częścią sterty, nie nakazuje to, aby pamięć przydzielona w obszarze metody podlegała usuwaniu śmieci lub innym zachowaniom, które byłyby powiązane z normalnymi strukturami danych przydzielonymi do sterty.

 76
Author: Duane Moore,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-16 05:27:37

Jak wyjaśnia Ta odpowiedź, dokładna lokalizacja puli łańcuchów nie jest określona i może się różnić w zależności od implementacji JVM.

Warto zauważyć, że do Javy 7 Pula znajdowała się w przestrzeni permgen sterty na hotspocie JVM, ale została przeniesiona do głównej części sterty od czasu Javy 7:

Obszar : HotSpot
Synopsis: w JDK 7 internowane ciągi nie są już przydzielane do stałego pokolenia Java heap, ale są zamiast tego przydzielane w głównej części Java heap (znane jako Młode i stare pokolenia), wraz z innymi obiektami utworzonymi przez aplikację. Zmiana ta spowoduje, że więcej danych będzie przebywać w głównej stercie Java, a mniej danych w generowaniu permanentnym, a zatem może wymagać dostosowania rozmiarów sterty. Większość aplikacji będzie widzieć tylko stosunkowo niewielkie różnice w użyciu sterty z powodu tej zmiany, ale większe aplikacje, które ładują wiele klas lub zrobić ciężkie użycie Sznurka.metoda intern () zauważy bardziej znaczące różnice. Rfe: 6962931

I w Javie 8 Hotspot, permanent Generation został całkowicie usunięty.

 57
Author: assylias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:09:58

Literały łańcuchów nie są przechowywane na stosie. Nigdy. W rzeczywistości na stosie nie są przechowywane żadne obiekty.

Literały łańcuchowe (a dokładniej obiekty łańcuchowe, które je reprezentują) były historycznie przechowywane w stercie zwanej" permgen". (Permgen to skrót od permanent generation.)

W normalnych okolicznościach literały ciągów i wiele innych rzeczy w stercie permgen są" trwale " osiągalne i nie są zbierane. (Na przykład, Literały łańcuchów są zawsze osiągalne z obiektów kodu, które ich używają.) Można jednak skonfigurować JVM tak, aby próbował znaleźć i zebrać dynamicznie ładowane klasy, które nie są już potrzebne, a to może spowodować, że literały łańcuchów będą zbierane jako śmieci.

Wyjaśnienie #1 - nie mówię, że Permgen nie dostaje GC ' ed. Tak, zazwyczaj, gdy JVM zdecyduje się uruchomić pełną GC. Chodzi mi o to, że ciąg literały będą osiągalne tak długo, jak kod, który używa są one osiągalne, a kod będzie dostępny tak długo, jak jego classloader jest osiągalny, a dla domyślnych classloaderów oznacza to "na zawsze".

Wyjaśnienie # 2 - W rzeczywistości Java 7 i Później używa zwykłej sterty do przechowywania puli ciągów. Tak więc obiekty łańcuchowe, które reprezentują literały łańcuchowe i łańcuchy intern ' D, są w rzeczywistości w regularnym stosie. (Zobacz odpowiedź @asylias po szczegóły.)


Ale wciąż staram się znaleźć cienką linię między przechowywanie znaków literalnych i znaków utworzonych za pomocą new.

Nie ma "cienkiej linii". To naprawdę bardzo proste:

  • String obiekty reprezentujące / odpowiadające literałom łańcuchów są przechowywane w Puli łańcuchów.
  • String obiekty utworzone przez wywołanie String::intern są przechowywane w Puli łańcuchów.
  • wszystkie inne String obiekty nie są przechowywane w Puli łańcuchów.

Wtedy jest osobne pytanie, gdzie pula łańcuchów jest "przechowywana". Prior do Javy 7 była to sterta permgen. Począwszy od Java 7 jest to sterta główna.

 30
Author: Stephen C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-16 01:38:27

String pooling

String pooling (czasami nazywany także kanonikalizacją łańcuchów) jest proces zamiany kilku obiektów łańcuchowych na równe wartości, ale Inna tożsamość z pojedynczym współdzielonym obiektem String. Możesz osiągnąć ten cel poprzez utrzymanie własnej mapy (z ewentualnie miękkim lub słabe referencje w zależności od wymagań) i za pomocą mapy wartości jako wartości kanoniczne. Możesz też użyć sznurka.metoda intern () który jest dostarczany przez JDK.

W czasach Javy 6 używając String.stażysta () był zakazany przez wielu standardy ze względu na dużą możliwość uzyskania OutOfMemoryException jeśli połączenie wymknęło się spod kontroli. Oracle Java 7 implementation of string podział został znacznie zmieniony. Szczegóły znajdziesz w http://bugs.sun.com/view_bug.do?bug_id=6962931 i http://bugs.sun.com/view_bug.do?bug_id=6962930 .

Sznurek.intern() w Javie 6

In those good old days wszystkie internowane ciągi były przechowywane w PermGen - część o stałej wielkości stosu używana głównie do przechowywania załadowanych klas i basen strunowy. Oprócz wyraźnie internowanych ciągów, ciąg PermGen pool zawierał również wszystkie dosłowne ciągi używane wcześniej w programie (użyte jest tu ważne słowo – jeśli klasa lub metoda nigdy nie loaded/called, żadne stałe w nim zdefiniowane nie zostaną załadowane).

Największym problemem z taką pulą ciągów w Javie 6 była jej lokalizacja – PermGen. PermGen ma stały rozmiar i nie można go rozszerzyć w runtime. Można go ustawić za pomocą opcji-XX: MaxPermSize=96m. As far as I domyślna wielkość PermGen waha się między 32M a 96M w zależności od Peron. Możesz zwiększyć jego rozmiar, ale jego rozmiar nadal będzie naprawione. Takie ograniczenie wymagało bardzo starannego użycia Sznurka.stażysta – lepiej nie internować żadnych niekontrolowanych danych Użytkownika za pomocą tej metody. Dlatego też string pooling w czasach Javy 6 był najczęściej implementowany w na ręcznie zarządzane mapy.

Sznurek.intern() in Java 7

Inżynierowie Oracle wprowadzili niezwykle ważną zmianę w łańcuchu pooling logic in Java 7 – Pula łańcuchów została przeniesiona do sterty. Oznacza to, że nie jesteś już ograniczony oddzielnym stałym rozmiarem obszar pamięci. Wszystkie łańcuchy znajdują się teraz w stercie, jak większość innych zwykłych obiektów, co pozwala zarządzać tylko wielkością sterty podczas dostrajanie aplikacji. Technicznie, to samo może być wystarczającym powód, aby ponownie rozważyć użycie String.intern() w Twoich programach Java 7. Ale są inne powody.

Wartości puli łańcuchów są zbierane jako śmieci

Tak, wszystkie ciągi w Puli ciągów JVM kwalifikują się do śmieci kolekcja, jeśli nie ma do nich odniesień z Twoich korzeni programu. Dotyczy to wszystkich omawianych wersji Javy. Oznacza to, że jeśli twój internowany ciąg wyszedł poza zakres i nie ma innych odniesień do Informatyka – to będą śmieci zbierane z puli ciągów JVM.

Jest uprawniony do odbioru śmieci i zamieszkania w stercie, JVM Pula strun wydaje się być właściwym miejscem dla wszystkich twoich strun, prawda? Teoretycznie to prawda – nieużywane ciągi będą śmieciami pobieranymi z puli, używane ciągi pozwolą na zapisanie pamięci w przypadku, gdy pobiera równy ciąg z wejścia. Wydaje się być doskonałym wspomnieniem strategia Oszczędzania? Prawie tak. Musisz wiedzieć jak wygląda Pula sznurków wdrożone przed podjęciem jakichkolwiek decyzji.

Źródło.

 23
Author: Trying,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-28 12:23:07

Jak wyjaśniają inne odpowiedzi pamięć w Javie jest podzielona na dwie części

1. Stos: jeden stos jest tworzony dla każdego wątku i przechowuje ramki stosu, które ponownie przechowują zmienne lokalne i jeśli zmienna jest typem odniesienia, to ta zmienna odnosi się do lokalizacji pamięci w stercie dla rzeczywistego obiektu.

2. Heap: Wszystkie rodzaje obiektów będą tworzone tylko w heap.

Pamięć sterty jest ponownie podzielona na 3 części

1. Młode Pokolenie: Przechowuje obiekty o krótkim życiu, samo młode pokolenie można podzielić na dwie kategorie Eden Spacei Survivor Space.

2. Stara generacja: przechowuje obiekty, które przetrwały wiele cykli zbierania śmieci i nadal są przywoływane.

3. Permanent Generation: przechowuje metadane dotyczące programu, np. runtime constant pool.

String constant pool należy do stałego obszaru generowania pamięci sterty.

Możemy zobacz pulę stałą runtime dla naszego kodu w kodzie bajtowym za pomocą javap -verbose class_name, która wyświetli nam odwołania do metod (#Methodref), obiekty klasy (#Class), literały łańcuchowe (#String)

runtime-constant-pool

Możesz przeczytać więcej na ten temat w moim artykule Jak JVM radzi sobie z Przeciążaniem i nadpisywaniem metod wewnętrznie .

 11
Author: Naresh Joshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-10 06:33:51

Do wspaniałych odpowiedzi, które już tu zawarte, chcę dodać coś, czego brakuje w mojej perspektywie-ilustrację.

Jak juĹź juĹź JVM dzieli przydzielonä ... pamiÄ ™ Ä ‡ do programu Java na dwie czÄ ™ Ĺ " ci. jeden to stack , a drugi to stop. Stos jest używany do celów wykonawczych, A sterta do celów przechowywania. W tej pamięci sterty, JVM przydziela część pamięci przeznaczoną specjalnie dla literałów ciągów. Ta część pamięci sterty nazywa się string Pula stałych .

Więc na przykład, jeśli init następujących obiektów:

String s1 = "abc"; 
String s2 = "123";
String obj1 = new String("abc");
String obj2 = new String("def");
String obj3 = new String("456);

Literały łańcuchów s1 i s2 trafią do stałej puli łańcuchów, obiekty obj1, obj2, obj3 do sterty. Wszystkie z nich zostaną odwołane ze stosu.

Należy również pamiętać, że " abc " pojawi się w stercie i w ciągach stałych pool. Dlaczego String s1 = "abc" i String obj1 = new String("abc") będą tworzone w ten sposób? To dlatego, że String obj1 = new String("abc") jawnie tworzy nową i referencyjną odrębną instancję ciągu znaków object i String s1 = "abc" mogą ponownie użyć instancji ze stałej puli łańcuchów, jeśli taka jest dostępna. Dla bardziej rozbudowanego wyjaśnienia: https://stackoverflow.com/a/3298542/2811258

Tutaj wpisz opis obrazka

 10
Author: Johnny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-10 11:38:42