intern()
intern() 메서드는 문자열을 복사하는 역할을 하는 메서드이다. 무작정 복사하는 것이 아니라, 이미 존재하는 문자열일 경우에는 기존 문자열을 참조하기도 한다. intern() 메서드의 동작 과정은 아래와 같다.
1. intern() 메서드로 호출된 문자열이 String constant pool에 존재하는지 확인
2. String constant pool에 존재할 경우 해당 문자열의 참조를 반환
3. 존재하지 않을 경우 String constant pool에 문자열을 저장하고 pool에 저장한 문자열의 참조를 반환
String constant pool이란?
문자열 상수 풀
리터럴 문자열을 저장하는 힙 영역 내에 존재하는 특별한 메모리 영역이다. 사용 목적과 이점은 아래와 같다.
1. 메모리 절약: 리터럴 문자열은 문자열 상수 풀에 저장되어 하나의 인스턴스로 유지된다. 동일한 문자열이 여러 곳에서 사용될 경우 계속 문자열을 생성하는 것이 아니라 기존 상수 풀의 인스턴스를 참조하기 때문에 메모리를 절약할 수 있다는 장점이 있다.
2. 빠른 비교: 문자열 상수 풀을 통해 래퍼런스 비교를 하기 때문에 비교가 빠르다는 장점이 있다. '==' 연산자를 통해 객체의 주소를 비교하는 래퍼런스 비교를 하기 때문에 문자열 값 자체를 비교하는 equals() 메서드보다 비교가 빠르다.
3. 문자열 연결 최적화: 연산하려는 문자열이 상수 풀에 존재할 경우, 새로운 인스턴스를 생성하지 않고 기존 인스턴스를 사용하기 때문에 연산이 빠르다는 장점이 있다.
4. 문자열 리터럴의 불변성 보장: 문자열 상수 풀에 저장된 리터럴 문자열은 불변이 보장되므로 코드 안정성 및 다중 스레드 환경에서의 안정성을 보장한다.
즉 같은 내용의 문자열의 String constant pool 내 존재 여부에 따라 새로운 문자열을 저장할지, 기존 문자열의 참조를 반환할지 결정한다.
이 때 주의할 점이 데이터가 String constant pool에 저장되게 하기 위해서는 리터럴 방식( String example = "EXAMPLE" )으로 문자열을 생성하여야 한다. new 키워드(String example = new String("EXAMPLE"))를 통해 문자열을 생성할 경우에는 Heap 메모리에 저장된다.
아래의 예시를 통해 살펴보자.
public class InternTest {
public static void main(String[] args) {
String literalStr1 = "STRING"; // 상수 풀에 저장
String newStr1 = new String("STRING"); // 힙 메모리에 저장
String internStr = literalStr1.intern(); // 상수풀에 "STRING"이 이미 존재하므로 해당 literalStr1의 참조를 반환
String literalStr2 = "STRING"; // 이미 상수 풀에 존재하는 문자열인 literalStr1을 참조
System.out.println(literalStr1 == newStr1); // false
System.out.println(literalStr1 == internStr); // true
System.out.println(literalStr1 == literalStr2); // true
}
}
public class InternTest {
public static void main(String[] args) {
String newStr1 = new String("STRING"); // 힙 메모리에 저장
String internStr = newStr1.intern(); // newStr1은 상수 풀에 존재하지 않기 때문에 상수 풀에 String 저장 후 반환
String literalStr1 = "STRING"; // 상수 풀에 이미 존재하는 "STRING" internStr 참조 반환
String newStr2 = new String("STRING"); // 힙 메모리에 저장(새로운 문자열 생성)
System.out.println(newStr1 == internStr); // false
System.out.println(internStr == literalStr1); // true
System.out.println(newStr1 == newStr2); // false
}
}
String은 GC의 대상인가?
String 또한 GC의 대상이다. 다만 리터럴 문자열이 저장되는 문자열 상수 풀의 위치의 변화가 있었다.
자바 7 버전 이전의 String constant pool은 메모리의 PermGen(Permanent Generation)이라는 클래스, 필드, 메서드, 어노테이션 등의 메타 데이터를 저장하는 영역에 저장되었다. 클래스 로더의 클래스 로드 및 언로드와 리터럴 문자열이 쌓임에 따라 해당 PermGen의 메모리가 부족해지고 OutOfMemoryError가 발생하는 문제가 있었다. PermGen 공간의 크기 자체 또한 동적으로 조정되지 않는 고정 크기였기 때문에 해당 문제를 해결하기가 어려웠다.
자바 7 이후로 PermGen 영역은 Metaspace 영역으로 대체되게 되었다. 기존 PermGen 영역 내에 존재하던 문자열 상수 풀 또한 힙 영역 내로 이동하였으며 해당 문제는 해결되었다.
리터럴 문자열 생성 vs intern()
리터럴로 문자열을 생성할 경우에도 상수 풀에 문자열을 저장하고, intern() 또한 상수 풀에 문자열을 저장한다.
두 방식 모두 메모리 사용량을 줄이기 위해서 상수 풀에 문자열 값을 저장하고 호출한다.
물론 두 방식마다 저장 시점에 따른 차이는 존재한다. 리터럴의 경우 컴파일 시 상수 풀에서 문자열이 저장되고 intern()의 경우 런타임 시점에 상수 풀에서 문자열 검색과 저장이 이루어진다.
복사하려는 문자열이 동적으로 런타임 시점에서 생성되는 경우에는 intern()을 사용하는 것이 적합하고 문자열이 코드 상에 명시적으로 작성되어 있는 경우에는 그냥 리터럴을 사용하는 것이 적합하다.
1. 동적으로 런타임 중에 생성되는 문자열을 복사하는 경우 intern() 사용
public class InternTest {
public static void main(String[] args) {
String newStr1 = new String("STRING"); // 런타임 시점에 동적으로 힙 영역에 문자열 저장
String internStr = newStr1.intern(); // newStr1은 상수 풀에 존재하지 않기 때문에 상수 풀에 String 저장 후 참조 반환
System.out.println(newStr1 == internStr); // false
}
}
2. 명시적으로 작성된 문자열을 컴파일 시점에 복사하고 싶은 경우
public class InternTest {
public static void main(String[] args) {
String literalStr1 = "STRING"; // "STRING" 문자열 상수 풀에 추가
String literalStr2 = "STRING"; // 이미 "STRING"이 존재하기 때문에 literalStr1 참조
System.out.println(literalStr1 == literalStr2); // true
}
}
References
https://gyoogle.dev/blog/computer-language/Java/Interend%20String%20in%20Java.html
Interned String in Java | 👨🏻💻 Tech Interview
Interned String in Java 자바(Java)의 문자열(String)은 불변(immutable)하다. String의 함수를 호출을 하면 해당 객체를 직접 수정하는 것이 아니라, 함수의 결과로 해당 객체가 아닌 다른 객체를 반환한다. 그
gyoogle.dev
https://kim-jong-hyun.tistory.com/55
[JAVA] - String이란?
JAVA로 개발하다보면 제일많이 쓰이는 클래스가 String 클래스인것같다. 이번장에서는 String에 대해 알아보자 String이란? String 클래스는 문자열을 다루는 클래스이며 immutable 하다는 특징이 있다. imm
kim-jong-hyun.tistory.com
https://www.baeldung.com/string/intern
https://www.javatpoint.com/java-string-intern
Java String intern() method - javatpoint
Java String intern() method with method signature and examples of concat, compare, touppercase, tolowercase, trim, length, equals, split, string intern in java etc.
www.javatpoint.com
https://stackoverflow.com/questions/10578984/what-is-java-string-interning
What is Java String interning?
What is String Interning in Java, when I should use it, and why?
stackoverflow.com
'Java' 카테고리의 다른 글
[Java] 가비지 컬렉션(Garbage Collection) (0) | 2024.04.06 |
---|---|
[Java] Stream(스트림) (1) | 2024.04.06 |
[Java] Record(레코드) (0) | 2024.04.06 |
[Java] Casting(캐스팅) (0) | 2024.04.05 |
[Java] Error & Exception(에러와 예외 클래스) (0) | 2024.04.04 |