본문 바로가기
Java/basic

String constant pool를 이해하면 왜 String이 불변으로 설계됬는지 이해할 수 있다

by Ellery 2022. 4. 13.

일단 method area(또는 클래스영역)의 runtime constant pool과는 별개의 영역이다. 구분해서 이해해야 함

  • runtime constant pool: 클래스 내의 final 제어자가 붙어있는 모든 상수들에 대한 symbol table을 관리(레퍼런스를 저장). 클래스 영역에 저장됨
  • String constant pool: 리터럴로 초기화된 String 변수값을 저장함. 힙 영역 내에 있는 String constant pool에 저장됨

https://www.tutorialsmate.com/2020/06/core-java-interview-questions.html

자바에서는 String을 어떻게 생성하느냐에 따라 리터럴값의 저장위치 차이가 생긴다. 

  • new로 생성하면 Heap 영역에 저장된다.
    • String pool에 존재하든 다른 같은 값의 객체가 있던 별개의 주소를 가진 객체
  • String 리터럴로 생성하면 해당 값은 Heap영역 내의 string constant pool에 저장됨(String interning)
    • String을 literal로 선언하면 내부적으로 String의 intern()메서드가 호출되면서 string constant pool을 탐색한다.
      같은 값이 있으면 주소를 반환해주고 없으면 constant pool에 넣고 새로운 주소를 반환한다
    • 따라서 리터럴로 생성된 String은 불변 객체이다. 
  • 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