String str = "hello";
String str2 = "hello";
System.out.println(str == str2); // true
위 코드에서 str == str2의 결과는 뭘까?
동등성과 동일성을 배웠다면 false로 예상했겠지만 결과는 true다.
"어라 자바에서 객체는 ==이 아니라 .equals()로 비교해야 문자열 비교가 되는 거 아니었나?"
그 이유는 JVM이 String Pool을 사용하기 때문이다.
String Constant Pool이란?
우선 Contant Pool이란 클래스 내에 사용되는 상수들을 담아놓은공간이다.
클래스 파일(.class)안에 테이블 형태로 들어가 있다.
이 Constant Pool에서 문자열 리터럴만을 별도로 관리하는 공간이 String Pool(String Constant Pool)이다.
String str = "hello";
str을 리터럴로 선언하게 되면 JVM은 String Pool이라는 곳에 "hello" 값과 동일한 문자열이 있는지 확인한다. 존재하지 않으면 String pool에 새롭게 추가한다.
String str = "hello";
String str2 = "hello";
이어 "hello"라는 값을 가진 문자열을 리터럴로 다시 생성하면 String Pool에 저장되어 있던 "hello"객체를 참조하여 재사용한다. (str2 = str1;)
String str3 = new ("hello"); // 별도의 Heap 메모리에 저장
하지만 `new` 키워드를 사용하면, 같은 문자열이라도 항상 새로운 객체가 힙(heap) 메모리에 생성된다.
때문에 문자열을 사용할 때는 메모리 관점에서 리터럴로 생성하는 게 좋다.
또 동적으로 생성되는 문자열(DB에서 조회해 오는 String, 파일에서 읽어 들인 String)의 경우에도 String Pool에 저장되지 않는다.
그러므로 동일한 문자열이어도 `==` 로 비교하면 결과는 false가 나오므로 문자열 비교를 위해서는 `equals`(동등연산)으로 비교해야 한다.
Java 7 버전부터 String Pool이 Method 영역에서 Heap 영역 내부로 옮겨지게 되면서 String pool에서도 GC가 수행되게 되어 메모리 부족 오류 위험 또한 줄어들게 되었다. 이로 인해 String Constant Pool은 Runtime에서 많은 양의 String 객체를 생성하게 되더라도 효율적인 메모리 관리가 가능해졌다.
String Constant Pool과 Runtime Constant Pool
String Constant Pool은 힙 영역, Runtime Constant Pool은 메서드 영역에 저장된다고 알고 있었다.
String Constant Pool은 Runtime Constant Pool의 하위 개념인데 왜 둘의 저장 위치가 다를까?라는 궁금증이 생겼다. (GC 공부하다가 왜 여기까지 나왔는지 모르겠지만)
Runtime Constant Pool
자바에서 Runtime Constant Pool은 클래스의 정적 데이터(클래스 메타데이터) 즉,
클래스 및 메서드 레벨의 다양한 상수(숫자 상수, 메서드 참조, 필드 참조 등)를 저장하는 곳이다.
각 클래스와 인터페이스마다 고유의 Runtime Constant Pool이 존재하며, JVM은 이를 통해 클래스 로드, 메서드 호출, 필드 접근 등의 작업을 수행한다.
왜 영역이 다른가?
Runtime Constant Pool
런타임 상수 풀
은 메서드 영역(Java 7까지는 PermGen, Java 8부터는 Metaspace)에 저장된다.
런타임 상수 풀은 클래스별로 존재하는데, 클래스 및 인터페이스의 상수 뿐만 아니라 메서드와 필드에 대한 모든 레퍼런스에 대한 정보를 가지고 있다.
String Constant Pool
String 객체는 기존 객체를 재사용하지 않고 생성할 때마다 새로운 객체가 생성되는 불변 객체이다.
보통 문자열은 동적으로 생성되는 경우가 많고, 필요하지 않은 문자열을 가비지 컬렉션을 통해 정리할 수 있기 때문에 문자열 상수 풀
을 힙 영역에 따로 두고 재사용하는 것이다.
요약하자면!
String Constant Pool은 Runtime Constant Pool의 논리적 하위 개념이지만, JVM의 메모리 관리 최적화를 위해 물리적으로 서로 다른 영역에 저장된다!
'💻 Dev > Java' 카테고리의 다른 글
JDK 8에서 Perm 영역이 삭제된 이유 (0) | 2024.11.25 |
---|---|
가비지 컬렉터(GC) feat.힙 영역 (0) | 2024.11.23 |
자바는 Call by Value만 사용한다. (0) | 2024.11.22 |
BigDecimal이란? (0) | 2024.10.30 |
Immutable(불변성), StringBuffer와 StringBuilder (0) | 2024.10.29 |
자바 코드의 메모리 영역(스택&힙) (0) | 2024.10.29 |