String Constant Pool의 이해


우연히 생활코딩에서 보게 된 글, 답은 당연히 false 라고 생각했지만 직접 돌려본 결과 true였다.

// true일까요 false 일까요?

String a = "aaa";
String b = "aaa";
if (a == b) {
    System.out.println("true");
} else {
    System.out.println("false");
}

[예제1] 객체 비교 문제



== 연산


Java 에서 == 연산은 객체의 주소값을 비교할 때 사용하고 

문자열의 값을 비교할 때는 equals 함수를 쓴다.


그런데 [예제1] 에서는 ==연산으로 비교했음에도 결과값은 왜 true를 반환할까



String Constant Pool 


답은 String Constant Pool 때문이었다.


먼저 String을 생성하는 방법은 대표적으로 2가지가 있다.

  1. new 연산자 방식
  2. literal을 이용한 방식


String a = new String("aaa"); // new 방식
String b = "aaa"; // literal 방식

[예제2] String 선언 방식



literal 로 String 을 선언한 경우 


String 객체는 내부적으로 intern() 메소드를 호출하게 된다.

intern 메소드는 String Constant Pool 에서 해당 문자열이 존재하는지 검색하고

존재하면 해당 문자열의 주소값을 반환

존재하지 않으면 새로운 주소값을 할당하여 반환한다.


이러한 동작원리에 따라 [예제1] 의 결과값은 true를 반환한다.



intern 메소드


명시적으로 intern 메소드를 호출하면 어떤 결과가 나올지 테스트해보았다.

String a = new String("aaa"); 
String b = "aaa"; 
String c = a.intern();

System.out.println(a == b); // false
System.out.println(b == c); // true


new 연산자로 선언한 a 와 literal 로 선언한 b 객체의 주소값은 다르지만

b와 a의 intern 메소드를 호출한 주소값(c)은 같았다.


따라서 literal 로 생성한 문자열은 스트링풀에 등록되고 내부적으로 고유의 인스턴스를 공유하는 것을 알 수 있다.



String Constant Pool 위치


Java6에서 스트링풀은 Perm 영역에 있었는데 

OutOfMemory(OOM) 문제로 Java7에서는 Heap 영역으로 변경되었다고 한다.


Perm 영역은 고정되어있고 Runtime 시에도 확장되지 않기때문에 Java6 이하 버전에서 intern 메소드를 자주 호출하면 OOM이 발생할 수 있다.



Heap 영역으로 변경 후 이점


Heap 영역으로 변경된 후 스트링 풀에 있는 문자열도 GC 대상이 된다.

따라서 효율적인 메모리 관리가 가능해진다.



스트링 풀 사이즈 설정


  • 스트링풀 사이즈는 -xx:StringTableSize 옵션으로 설정이 가능하다. (디폴트 : 1009)
  • intern 메소드를 자주 사용한다면 사이즈는 디폴트 값보다 높게 설정해야한다.
  • 사이즈 값으로는 소수를 사용해야 한다. (예를 들면 1,000,003)






참고 : https://medium.com/@joongwon/string-%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B3%A0%EC%B0%B0-57af94cbb6bc

'Language > Java' 카테고리의 다른 글

자바 커뮤니티1 - Class  (0) 2019.05.22
Java 문자열 객체  (0) 2018.08.04
Java 배열 선언, 초기화  (0) 2018.08.04
Java 접근지정자 (Access Modifier)  (0) 2018.08.04
Comparator 인터페이스를 이용한 다중 정렬  (0) 2018.08.01

+ Recent posts