일단 method area(또는 클래스영역)의 runtime constant pool과는 별개의 영역이다. 구분해서 이해해야 함
- runtime constant pool: 클래스 내의 final 제어자가 붙어있는 모든 상수들에 대한 symbol table을 관리(레퍼런스를 저장). 클래스 영역에 저장됨
- String constant pool: 리터럴로 초기화된 String 변수값을 저장함. 힙 영역 내에 있는 String constant pool에 저장됨
자바에서는 String을 어떻게 생성하느냐에 따라 리터럴값의 저장위치 차이가 생긴다.
- new로 생성하면 Heap 영역에 저장된다.
- String pool에 존재하든 다른 같은 값의 객체가 있던 별개의 주소를 가진 객체
- String 리터럴로 생성하면 해당 값은 Heap영역 내의 string constant pool에 저장됨(String interning)
- String을 literal로 선언하면 내부적으로 String의 intern()메서드가 호출되면서 string constant pool을 탐색한다.
같은 값이 있으면 주소를 반환해주고 없으면 constant pool에 넣고 새로운 주소를 반환한다 - 따라서 리터럴로 생성된 String은 불변 객체이다.
- String을 literal로 선언하면 내부적으로 String의 intern()메서드가 호출되면서 string constant pool을 탐색한다.
- Java에서 불변 객체를 이용하는 이유는 자바를 직접 만든 제임스 고슬링에 따르면 캐싱, 보안, 복사가 필요없는 빠른 재사용성, 동기화 성능 때문이라고 한다.
- 보안적인 이슈: 만약 네트워크 통신을 통해서 받은 ID와 password String이 mutable하다면 validation을 거친 이후에도 받아온 String이 안전한지 알수 없다.
- 동기화 이슈: 애초에 변경 불가능한 불변객체이면 여러 쓰레드에서 접근해도 thread-safe하다
- String.hashCode() 이용한 캐싱: String이 불변객체이므로 이를 키값으로 이용한 해싱 컬렉션의 퍼포먼스가 향상된다(hashcode()로 정수값을 받아 키값으로 이용하도록 컬렉션들이 설계되어 있음). 이 방식은 String pool에서도 사용되서 결과적으로 기존에 캐싱된 String값이 있는지 빠르게 조회할 수 있다.
String constant pool에 문자열 리터럴을 캐싱하고 이후에 재사용하게 되면 힙 메모리 영역을 효율적으로 사용할 수 있게 된다.
String a = "ellery"
String b = "ellery"
String c = new String("ellery");
assertThat(a).isSameAs(b); // true
assertThat(a).isNotSameAs(c); // true
JDK 6까지는 String constant pool의 위치는 Perm 영역으로, 힙 밖에 이 영역이 고정사이즈라 생기는 OOM(out of memory) 문제 때문에 7 이후 heap영역에 있게 됨. 따라서 String 객체들도 GC에 의해 할당해제되면서 메모리 관리가 된다.
참고:
https://www.baeldung.com/jvm-constant-pool
https://www.baeldung.com/java-string-immutable
https://www.baeldung.com/java-immutable-object
https://www.artima.com/articles/james-gosling-on-java-may-2001#part13
'Java > basic' 카테고리의 다른 글
자바 변수의 종류, 특징 - Primitive type, Reference type (0) | 2022.10.30 |
---|---|
JIT 컴파일러 동작과정 (0) | 2022.10.30 |
JVM 이란? (0) | 2022.10.30 |
JVM 아키텍쳐 구성요소 (0) | 2022.04.07 |
JDK, JRE의 차이 (0) | 2022.04.07 |