연관글
Java의 문자열(String) 객체가 저장되는 String Pool에 대하여
Java에서 가장 많이 사용되는 데이터 타입은
String
이 아닐까 싶습니다. 사람이 가장 이해하기 쉬운것이 Text이기 때문이지요. 그런데 Java에서 문자열을 표현하는 String
타입의 객체는 불변성
(Immutable)이라는 성질을 가지고 있으며 같은값의 문자열에 대해서는 단 하나의 문자열 객체만을 생성하도록 설계 되어있습니다.Java에서 String이 이러한 성질을 갖는 이유는 몇가지 장점이 있기 때문인데 가장 큰 장점은 성능입니다. 같은 값을 갖는 문자열 객체는
JVM
의 객체가 생성되는 공간인 Heap
에 매번 새로 생성하게 되면 메모리 공간적 측면에서 비효율적이기 때문이지요. 즉 문자열 객체를 캐싱
(Caching) 하는것입니다. 문자열의 불변성에 대한 자세한 내용은 상단의 연관글
을 참고해주시기 바랍니다.String Pool과 String Interning(문자열 객체의 억류)
Java의 Heap에는
String Pool
이라는 특별한 영역에서 String 객체들을 관리합니다. 이 String Pool의 실체는 HashMap
입니다. 다음 코드와 같이 문자열 리터럴을 사용하여 String 객체를 생성하면 String Pool
에 기존에 같은 값을 가지는 String 객체가 있는지 검사하고 있으면 그 객체의 참조값을, 없으면 String Pool에 새로 String 객체를 생성하고 그 참조값을 리턴합니다.
String a = "aaa";
String b = "aaa";
boolean isSame = a == b; //true |
cs |
이러한 과정을
intern
이라고 하며, String 객체를 위의 코드처럼 리터럴로 생성하는 경우에 내부적으로 intern()
이라는 메서드를 실행하여 수행합니다. 따라서 같은 값의 문자열인 a
, b
두 객체를 비교하면 참조값을 비교( ==
)하는 경우에도 true
임을 알 수 있습니다.
리터럴을 이용한 String 생성과 new String()을 이용한 String 생성의 차이
모르는 분이 계실지도 모르지만 문자열은 리터럴을 할당하는것만으로도 생성이 가능하지만
new
연산자와 String() 생성자
를 통해서도 생성이 가능합니다. 그럼 이 둘의 차이점은 무엇일까요?
String a = "aaa";
String b = "aaa";
String c = new String("aaa");
String d = new String("aaa"); |
cs |
이 둘의 가장 큰 차이점은 객체가 생성되는 영역입니다. 앞서 말했듯이 리터럴을 이용하여 생성하는 경우인 a와 b는 String Pool에 생성되어있는 String 객체를 가리킵니다.
반대로
new String("aaa")
으로 실행한 c
와 d
의 경우 일반 객체들과 마찬가지로 String Pool이 아닌 Heap
의 영역에 생성됩니다. String Pool도 엄밀히 따지면 Heap의 내부에 있지만 여기서는 다른 영역으로 생각해주세요.(이부분은 이후에 다룸) 즉 메모리상으로 보면 a, b, c, d 참조변수들은 아래와 같이 각각의 String 객체를 가리키고 있습니다.위 그림을 바탕으로 테스트를 해보도록 하죠. 결과는 다음과 같습니다.
String a = "aaa";
String b = "aaa";
String c = new String("aaa");
String d = new String("aaa");
System.out.println(a == b); //true
System.out.println(a == c); //false
System.out.println(c == d); //false
System.out.println(a.equals(b)); //true
System.out.println(a.equals(c)); //true
System.out.println(c.equals(d)); //true |
cs |
String Pool은 정확이 어디에 있는지
앞서
String Pool
의 위치가 JVM의 heap
영역이라고만 소개했습니다. heap
영역인것은 맞지만 정확히는 버전에 따라 조금 다릅니다. Java6
버전까지는 JVM Heap내부의 PermGen
영역에 있었으며, 그러한 이유로 String Pool에 문자열 객체가 많이 생성된다거나 다른 이유로 이 영역이 가득 차게되면 OutOfMemory
에러가 발생했습니다. PermGen 영역의 경우 객체가 가득차더라도 Runtime(실행중) 환경에서는 메모리를 동적으로 늘리지 못하기 때문입니다.Java7 부터는 다른 일반 객체들과 마찬가지고
Perm
영역이 아닌 Heap
에 String Pool을 생성합니다. 따라서 OOME가 발생했을때의 위험성을 이전부터 줄였다고 합니다.참고글
'자바[Java]' 카테고리의 다른 글
[JAVA] Lombok이란? Lombok 적용하는 방법 (3) | 2020.02.13 |
---|---|
[Effective Java] 인스턴스화가 필요없는 Utility 클래스 등은 private 생성자를 사용하자 (0) | 2019.07.16 |
[Effective Java] 문자열 String 영어 대소문자 무시하여 비교시에는 equalsIgnoreCase() 메서드를 사용하자. (0) | 2019.07.11 |
[JAVA] Java I/O(입출력) [2] 자바 입출력 패키지(java.io) 구조 (1) | 2019.07.11 |
[Java] String의 더하기 연산으로 인한 문제점과 StringBuffer, StringBuilder의 특성과 차이점에 대해서 (0) | 2019.06.22 |