Znam koncepcję puli stałych i puli stałych String używanej przez maszyny JVM do obsługi literałów String. Ale nie wiem, jaki typ pamięci jest używany przez maszynę JVM do przechowywania literałów stałych typu String. Stos 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 odwołuje się do niego żadna instancja, literał musi zostać zebrany przez uruchomienie GC (popraw mnie, jeśli się mylę), więc jak to jest obsługiwane, jeśli jest przechowywany na stosie?
104
Odpowiedzi:
Technicznie nie ma odpowiedzi. Zgodnie ze specyfikacją maszyny wirtualnej języka Java obszar przechowywania literałów łańcuchowych znajduje się w puli stałych czasu wykonywania . Obszar pamięci stałej puli czasu wykonywania jest przydzielany na podstawie klasy lub interfejsu, więc nie jest w ogóle powiązany z żadnymi instancjami obiektów. Pula stałych czasu wykonywania jest podzbiorem obszaru metod, który „przechowuje struktury klas, takie jak pula stałych czasu wykonywania, dane pól i metod oraz kod metod i konstruktorów, w tym metody specjalne używane podczas inicjowania i interfejsu klas i instancji inicjalizacja typu ”. Specyfikacja VM mówi, że chociaż obszar metody jest logicznie częścią sterty, nie narzuca, że pamięć przydzielona w obszarze metody podlega czyszczeniu pamięci lub innym zachowaniom, które byłyby związane z normalnymi strukturami danych przydzielonymi do sterty.
źródło
Jak wyjaśniono w tej odpowiedzi , dokładna lokalizacja puli ciągów nie jest określona i może się różnić w zależności od implementacji maszyny JVM.
Warto zauważyć, że do wersji Java 7 pula znajdowała się w obszarze permgen stosu w wirtualnej maszynie wirtualnej hotspot, ale została przeniesiona do głównej części sterty od wersji Java 7 :
A w Java 8 Hotspot, Permanent Generation zostało całkowicie usunięte.
źródło
Literały ciągów nie są przechowywane na stosie. Nigdy. W rzeczywistości na stosie nie są przechowywane żadne obiekty.
Literały ciągów znaków (lub dokładniej, obiekty, które je reprezentują String)
sąhistorycznie przechowywane w stercie zwany „PermGen” sterty. (Permgen to skrót od permanentnego generowania).W normalnych okolicznościach literały String i wiele innych rzeczy w stercie permgen jest „trwale” osiągalne i nie są zbierane jako śmieci. (Na przykład literały ciągów są zawsze dostępne z obiektów kodu, które ich używają). Można jednak skonfigurować maszynę JVM tak, aby próbowała znaleźć i zebrać klasy ładowane dynamicznie, które nie są już potrzebne, co może spowodować, że literały String zostaną wyrzucone do pamięci. .
WYJAŚNIENIE # 1 - Nie mówię, że Permgen nie otrzymuje GC. Dzieje się tak, zazwyczaj gdy maszyna JVM decyduje się na uruchomienie pełnego GC. Chodzi mi o to, że literały String będą osiągalne tak długo, jak długo kod, który ich używa, będzie osiągalny, a kod będzie osiągalny tak długo, jak długo jest osiągalny moduł ładujący klasy kodu, a dla domyślnych klas ładujących oznacza to „na zawsze”.
WYJAŚNIENIE # 2 - W rzeczywistości Java 7 i nowsze wersje używają zwykłej sterty do przechowywania puli ciągów. W ten sposób obiekty String, które reprezentują literały String i łańcuchy intern'd, znajdują się w rzeczywistości w zwykłej stercie. (Zobacz odpowiedź @ assylias, aby uzyskać szczegółowe informacje).
Nie ma „cienkiej linii”. To naprawdę bardzo proste:
String
obiekty, które reprezentują / odpowiadają literałom ciągów, są przechowywane w puli ciągów.String
obiekty utworzone przezString::intern
wywołanie są przechowywane w puli ciągów.String
przedmioty NIE są trzymane w puli strun.Następnie pojawia się oddzielne pytanie, gdzie pula ciągów jest „przechowywana”. Przed Java 7 był to stos permgen. Od wersji Java 7 jest to główna kupa.
źródło
Łączenie strun
String.intern () w Javie 6
String.intern () w Javie 7
Wartości puli ciągów są zbierane jako elementy bezużyteczne
źródło.
źródło
Jak wyjaśniają inne odpowiedzi, pamięć w Javie jest podzielona na dwie części
1. Stos: jeden stos jest tworzony na wątek i przechowuje ramki stosu, które ponownie przechowują zmienne lokalne, a jeśli zmienna jest typem referencyjnym, wówczas ta zmienna odnosi się do miejsca w pamięci w stercie dla rzeczywistego obiektu.
2. Sterta: Wszystkie rodzaje obiektów będą tworzone tylko w stercie.
Pamięć sterty jest ponownie podzielona na 3 części
1. Young Generation: Przechowuje przedmioty, które mają krótkie życie. Samo Young Generation można podzielić na dwie kategorie Eden Space i Survivor Space .
2. Stara generacja: Przechowuj obiekty, które przetrwały wiele cykli czyszczenia pamięci i nadal są przywoływane.
3. Trwałe generowanie: Przechowuje metadane dotyczące programu, np. Pula stałych czasu wykonywania.
Pula stałych ciągów należy do obszaru stałego generowania pamięci sterty.
Możemy zobaczyć pulę stałych czasu wykonywania dla naszego kodu w kodzie bajtowym, używając,
javap -verbose class_name
które pokaże nam referencje do metod (#Methodref), obiekty klas (#Class), literały ciągów (#String)Możesz przeczytać więcej na ten temat w moim artykule Jak JVM obsługuje wewnętrzne przeciążanie i zastępowanie metod .
źródło
Do świetnych odpowiedzi, które już tu zawarłem, chcę dodać coś, czego mi brakuje - ilustrację.
Jak już masz, JVM dzieli przydzieloną pamięć dla programu Java na dwie części. jeden to stos, a drugi to sterta . Stos jest używany do celów wykonania, a sterta jest używana do przechowywania. W tej pamięci sterty JVM przydziela trochę pamięci przeznaczonej specjalnie dla literałów łańcuchowych. Ta część pamięci sterty jest nazywana pulą stałych ciągów .
Na przykład, jeśli zainicjujesz następujące obiekty:
Literały łańcuchowe
s1
is2
przejdą do puli stałych łańcuchów, obiektów obj1, obj2, obj3 do sterty. Wszystkie z nich będą przywoływane ze stosu.Należy również zauważyć, że „abc” pojawi się w stercie i puli stałych łańcuchowych. Dlaczego jest
String s1 = "abc"
iString obj1 = new String("abc")
będzie tworzone w ten sposób? Dzieje się tak, ponieważString obj1 = new String("abc")
jawnie tworzy nowe i referencyjnie odrębne wystąpienie obiektu String iString s1 = "abc"
może ponownie użyć wystąpienia z puli stałych ciągów, jeśli jest dostępna. Bardziej szczegółowe wyjaśnienie: https://stackoverflow.com/a/3298542/2811258źródło