Java의 String 상수 풀은 힙과 스택 중 어디에 있습니까?
JVM이 문자열 리터럴을 처리하기 위해 사용하는 상수 풀과 문자열 상수 풀의 개념을 알고 있습니다.그러나 JVM이 문자열 상수 리터럴을 저장하기 위해 사용하는 메모리 유형은 알 수 없습니다.스택이야 힙이야?인스턴스와 관련되지 않은 리터럴이기 때문에 스택에 저장되어 있을 것으로 생각합니다.그러나 어떤 인스턴스에서 참조되지 않으면 GC 실행에서 리터럴을 수집해야 합니다(잘못된 경우 수정). 스택에 저장되어 있는 경우 리터럴은 어떻게 처리됩니까?
답은 엄밀히 말하면 둘 다 아니다.Java Virtual Machine 규격에 따르면 문자열 리터럴을 저장하는 영역은 런타임 상수 풀에 있습니다.런타임 상수 풀 메모리 영역은 클래스별 또는 인터페이스별로 할당되므로 개체 인스턴스에 전혀 연결되지 않습니다.런타임 상수 풀은 "런타임 상수 풀, 필드 및 메서드 데이터와 같은 클래스별 구조와 클래스 및 인스턴스 초기화 및 인터페이스 유형 초기화에 사용되는 특수 메서드를 포함한 메서드 및 생성자의 코드를 저장하는 메서드 영역의 하위 집합입니다.VM 사양에 따르면 메서드 영역이 논리적으로 힙의 일부이지만 메서드 영역에 할당된 메모리가 가비지 수집 또는 힙에 할당된 일반 데이터 구조와 관련된 기타 동작의 대상이 되는 것은 아닙니다.
이 답변에서 설명한 바와 같이 문자열 풀의 정확한 위치는 지정되지 않았으며 JVM 구현마다 다를 수 있습니다.
Java 7 이전까지는 풀이 핫스팟 JVM 힙의 permgen 공간에 있었지만 Java 7 이후 힙의 주요 부분으로 이동했다는 점에 주목하십시오.
영역: 핫스팟
개요:JDK 7에서는 내장 문자열은 Java 힙의 영구 세대에 할당되지 않고 어플리케이션에 의해 작성된 다른 오브젝트와 함께 Java 힙의 주요 부분(신세대 및 구세대로 알려져 있음)에 할당됩니다.이 변경으로 메인 Java 힙에 상주하는 데이터가 많아지고 영구 생성 데이터가 줄어들기 때문에 힙 크기를 조정할 필요가 있을 수 있습니다.대부분의 응용 프로그램은 이 변경으로 인해 힙 사용률에서 비교적 작은 차이만 볼 수 있지만, 많은 클래스를 로드하거나 String.intern() 메서드를 많이 사용하는 큰 응용 프로그램에서는 더 큰 차이를 볼 수 있습니다.RFE: 6962931
그리고 Java 8 Hotspot에서는 Permanent Generation이 완전히 제거되었습니다.
문자열 리터럴은 스택에 저장되지 않습니다.아니요. 실제로는 스택에 개체가 저장되지 않습니다.
String Literals(또는 보다 정확하게는 스트링 오브젝트)
하고 있다 permgen이라고 불리는 힙에 저장되어 있습니다(Permgen은 영구 생성의 약자입니다).
통상적인 상황에서는 스트링 리터럴 및 permgen 힙 내의 다른 대부분의 내용은 "영구적으로" 도달할 수 있으며 가비지 수집되지 않습니다(예를 들어 스트링 리터럴은 이를 사용하는 코드 개체에서 항상 도달할 수 있습니다).그러나 더 이상 필요하지 않은 동적으로 로드된 클래스를 검색 및 수집하도록 JVM을 구성할 수 있습니다. 그러면 문자열 리터럴이 가비지 수집될 수 있습니다.
명확화 #1 - 나는 Permgen이 GC를 받지 못했다고 말하는 것이 아니다.일반적으로는 JVM이 전체 GC를 실행하기로 결정할 때 실행됩니다.스트링 리터럴을 사용하는 코드가 도달 가능한 한 스트링 리터럴에 도달할 수 있으며, 코드의 클래스로더와 디폴트클래스로더의 경우 "영원히"를 의미합니다.
CLARIFICATION #2 - 실제로 Java 7 이후에는 일반 힙을 사용하여 문자열 풀을 유지합니다.따라서 String 리터럴 및 intern'd 문자열을 나타내는 String 객체는 실제로 일반 힙에 있습니다(자세한 내용은 @assylias's Answer 참조).
리터럴의 와 스트링 리터럴로 의 얇은 있습니다.
new
"얇은 선"은 없습니다.매우 간단합니다.
String
문자열 리터럴을 나타내거나 대응하는 객체는 문자열 풀에 저장됩니다.String
에String::intern
콜은 스트링 풀에서 보류됩니다.- 모든 것
String
이치노
다음으로 문자열 풀이 어디에 "저장"되어 있는지에 대한 별개의 문제가 있습니다.Java 7 이전에는 permgen 힙이었습니다.Java 7 이후로는 메인 힙입니다.
문자열 풀링
문자열 풀링(스트링 정규화라고도 함)은 동일한 값을 가지지만 다른 ID를 가진 여러 String 개체를 하나의 공유 String 개체로 대체하는 프로세스입니다.이 목표는 사용자 고유의 맵을 유지하고(요건에 따라 소프트 또는 약한 참조가 있을 수 있음) 지도 값을 정규화된 값으로 사용함으로써 달성할 수 있습니다.또는 JDK에서 제공하는 String.intern() 메서드를 사용할 수도 있습니다.
Java 6에서는 Out Of Memory를 얻을 가능성이 높기 때문에 String.intern()을 사용하는 것이 많은 표준에서 금지되어 있었습니다.풀링이 관리 범위를 벗어난 경우 예외입니다.문자열 풀링의 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의 String.intern()
옛날에는 모든 내부 문자열이 PermGen에 저장되었습니다.PermGen은 주로 로드된 클래스와 문자열 풀을 저장하는 데 사용되는 힙의 고정 크기 부분입니다.명시적으로 삽입된 문자열 외에 PermGen 문자열 풀에는 프로그램에서 이전에 사용된 모든 리터럴 문자열도 포함되어 있습니다(여기서 중요한 단어가 사용됩니다.클래스 또는 메서드가 로드/호출되지 않은 경우 정의된 상수는 로드되지 않습니다).
Java 6에서 이러한 문자열 풀의 가장 큰 문제는 위치인 PermGen이었습니다.PermGen은 크기가 고정되어 있어 실행 시 확장할 수 없습니다.-XX:MaxPermSize=96m 옵션을 사용하여 설정할 수 있습니다.디폴트 PermGen 사이즈는 플랫폼에 따라 32M에서 96M 사이즈가 다른 것으로 알고 있습니다.크기를 늘릴 수 있지만 크기는 변경되지 않습니다.이러한 제한으로 인해 String.intern을 매우 신중하게 사용해야 합니다.이 방법을 사용하여 제어되지 않은 사용자 입력을 삽입하지 않는 것이 좋습니다.이것이 Java 6에서 문자열 풀링이 대부분 수동으로 관리되는 맵에서 구현된 이유입니다.
Java 7의 String.intern()
Oracle 엔지니어는 Java 7의 문자열 풀링 논리에 매우 중요한 변경을 가했습니다.즉, 문자열 풀은 힙으로 재배치되었습니다.즉, 더 이상 고정 크기의 메모리 영역에 의해 제한되지 않습니다.이제 모든 문자열이 다른 대부분의 일반 개체와 마찬가지로 힙에 배치되므로 애플리케이션을 조정할 때 힙 크기만 관리할 수 있습니다.엄밀히 말하면 이것만으로도 Java 7 프로그램에서 String.intern() 사용을 재검토할 충분한 이유가 될 수 있습니다.하지만 다른 이유가 있다.
문자열 풀 값이 가비지 수집됨
예. 프로그램 루트에서 참조가 없는 경우 JVM 문자열 풀의 모든 문자열이 가비지 수집에 적합합니다.이는 모든 Java 버전에 적용됩니다.즉, 내부 문자열이 범위를 벗어나 다른 참조가 없는 경우 JVM 문자열 풀에서 가비지가 수집됩니다.
가비지 컬렉션에 적합하고 힙에 상주하는 JVM 문자열 풀은 모든 문자열에 적합한 장소인 것 같습니다.이론적으로는 그렇습니다.사용하지 않는 문자열은 풀에서 수집된 가비지입니다.사용된 문자열은 입력에서 동일한 문자열을 얻을 경우에 대비하여 메모리를 절약할 수 있습니다.완벽한 메모리 절약 전략인 것 같습니까?거의 비슷해요.결정을 내리기 전에 문자열 풀이 어떻게 구현되는지 알아야 합니다.
다른 답변이 설명하듯이 자바 메모리는 두 부분으로 나뉩니다.
1. 스택: 스레드당 1개의 스택이 생성되어 로컬 변수를 다시 저장하는 스택프레임을 저장합니다.변수가 참조 유형인 경우 해당 변수는 실제 객체의 힙 내 메모리 위치를 참조합니다.
2. 힙:모든 종류의 개체는 힙에만 생성됩니다.
히프 메모리는 다시 3개의 부분으로 분할됩니다.
1. 젊은 세대:수명이 짧은 오브젝트를 저장하는데, Young Generation 자체는 Eden Space와 Survivor Space 두 가지로 나눌 수 있습니다.
2. 구세대:여러 가비지 수집 주기에서 살아남아 여전히 참조 중인 개체를 저장합니다.
3. 영구 생성:프로그램에 대한 메타데이터(예: 런타임 상수 풀)를 저장합니다.
문자열 상수 풀은 힙 메모리의 영구 생성 영역에 속합니다.
바이트 코드의 코드에 대한 런타임 상수 풀은 다음을 사용합니다.javap -verbose class_name
메서드 참조(#Methodref), 클래스 오브젝트(#Class), 문자열 리터럴(#String)이 표시됩니다.
자세한 내용은 내 기사 "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
로, string constant pool로 합니다.모두 스택에서 참조됩니다.
'아주'라고 합니다.?는 왜?String s1 = "abc"
★★★★★★★★★★★★★★★★★」String obj1 = new String("abc")
이렇게 만들어질까요?★★★★★★★★★★★★★★★ String obj1 = new String("abc")
String 객체의 새로운 참조 고유 인스턴스를 명시적으로 만들고String s1 = "abc"
사용 가능한 경우 문자열 상수 풀의 인스턴스를 재사용할 수 있습니다.상세한 것에 대하여는, https://stackoverflow.com/a/3298542/2811258 를 참조해 주세요.
언급URL : https://stackoverflow.com/questions/4918399/where-does-javas-string-constant-pool-live-the-heap-or-the-stack
'itsource' 카테고리의 다른 글
오류 - npm - node.js를 사용하여 mariasql 패키지를 설치하는 중 (0) | 2023.02.06 |
---|---|
@Mock 주석 뒤에 있는 모의 인스턴스가 null입니다. (0) | 2023.02.06 |
PHP에서 정적 코드 분석을 수행하려면 어떻게 해야 합니까? (0) | 2023.02.06 |
단일 SQL 문의 열 헤더 출력을 억제하려면 어떻게 해야 합니까? (0) | 2023.02.06 |
팬더: 여러 열의 두 데이터 프레임을 병합(축소) (0) | 2023.02.06 |