연관글



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

이 둘의 가장 큰 차이점은 객체가 생성되는 영역입니다. 앞서 말했듯이 리터럴을 이용하여 생성하는 경우인 abString Pool에 생성되어있는 String 객체를 가리킵니다.

반대로 new String("aaa") 으로 실행한 cd의 경우 일반 객체들과 마찬가지로 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가 발생했을때의 위험성을 이전부터 줄였다고 합니다.




참고글
블로그 이미지

도로락

IT, 프로그래밍, 컴퓨터 활용 정보 등을 위한 블로그

댓글을 달아 주세요! 질문 환영합니다!