String.intern()

de_sj_awa·2021년 5월 8일
0

1. String 생성 방식

String은 두 가지 생성 방식이 있고 각각의 차이점이 존재한다.

  1. new 연산자를 이용한 방식
  2. 리터럴을 이용한 방식

두 가지 방식에는 큰 차이점이 있다. new를 통해 String을 생성하면 Heap 영역에 존재하게 되고 리터럴을 이용할 경우 string constant pool이라는 영역에 존재하게 된다.

다음의 예제 코드를 보자.

String literal = "loper";
String b = new String("loper");

System.out.println(literal == object);
System.out.println(literal.equals(object);

Java에서 == 연산은 객체의 주소값을 비교할 때 사용하고 값을 비교할 때는 equals() 함수를 쓴다. == 연산의 결과는 false이고 equals의 결과는 true이다. equals는 객체의 값을 비교하기 때문에 같은 문자열에 대해서 true가 나온다. 하지만 == 연산자의 경우 Heap 영역에 생성된 String 객체의 주소값을 비교하기 때문에 결과는 false가 나온다.

2. 동작 방식

literal로 String을 선언한 경우

String을 literal로 선언한 경우 내부적으로 String의 intern() 메소드가 호출된다. intern() 메소드는 주어진 문자열이 string constant pool에 존재하는지 검색하고, 있다면 그 주소값을 반환하고 없다면 string constant pool에 넣고 새로운 주소값을 반환한다.

String literal = "loper";
String object = new String("loper");
String intern = object.intern();

System.out.println(literal == object); //false
System.out.println(literal.equlas(object); //true
System.out.println(literal == intern); //true
System.out.println(literal.equals(intern)); //true

기존에 new를 통해 생성된 String 객체와 리터럴로 생성된 String 객체를 == 연산하였을 경우 false를 반환하였지만 new를 통해 생성된 String 객체의 intern() 메소드를 호출하여 새로운 String 객체에 대입하였을 경우 리터럴로 생성된 String 객체와 == 연산시 true를 반환하게 된다.

리터럴로 "loper"라는 문자열이 String constant pool에 저장되어 있고 intern() 메소드를 호출하면서 string constant pool에 "loper"라는 문자열을 검색하게 되고 이미 저장된 "loper" 문자열이 있기 때문에 동일한 주소값을 반환해 true를 반환하는 것이다.

3. intern()의 장점과 단점

intern() 메소드가 호출이 되면,

  1. string constant pool에 있는 각종 문자열에 equals()해서 같은게 있다면 그것을 반환하고,
  2. 같은게 없다면 string constant pool에 String object를 추가하고, 추가한 것을 반환한다.

intern은 Heap의 메모리를 아낄 수 있다는 장점이 있다.

하지만, intern() 메소드를 사용하는 단점도 있다.

  1. 우선 String 객체를 하나 만들어야 한다.
  2. String의 equals() 메소드를 이용해서 string constant pool에 있는 문자열을 찾아서 비교해야 한다. (시간이 걸림)
  3. String constant pool에 들어갔으므로, 더 이상 GC(가비지 컬렉션)의 대상이 될 수 없다. (메모리 관리 불가)

4. string constant pool의 위치

Java6에서 string constant pool의 위치는 Perm 영역에 있었는데 Perm 영역은 고정된 사이즈이고 Runtime 시에 사이즈가 확장되지 않기 때문에 OutofMemoryException을 발생시킬 수 있고 메모리 관리가 불가능하기 때문에 intern() 메소드를 사용하는 것이 권장되지 않았다.

그러나 Java 7에서 string constant pool의 위치가 Perm 영역에서 Heap 영역으로 변경되었다.

따라서, string constant pool에 있는 문자열도 GC의 대상이 되기 때문에 효율적인 메모리 관리가 가능해 졌다.

5. string constant pool의 사이즈 설정

  • string constant pool의 사이즈는 -xx:StringTableSize 옵션으로 설정이 가능하다. (default : 1009)
  • intern 메소드를 자주 사용한다면 사이즈는 디폴트 값보다 높게 설정해야 한다.
  • 사이즈 값으로는 소수를 지정하는 것이 성능에 도움이 된다. (ex) 60013)

참고

profile
이것저것 관심많은 개발자.

0개의 댓글