본문 바로가기
프로그래밍/Java

[Java] String Pool에 관하여

by 사바라다 2021. 1. 17.

안녕하세요. 오늘은 여러분들과 String Pool에 대해서 이야기해보고자 합니다. 알고 계셨나요 ? Java에서는 String을 저장하는데 2곳의 메모리를 사용할 수 있습니다. 오늘은 String Pool에 대해서 여러분들과 공유하고자 합니다.

String Interning

Java에서의 String은 일반적인 Heap에 저장할 수 있고 또한 별도의 String constants Pool이라는 공간을 제공하고 있습니다. String Constants Pool에 저장하고 사용하는 것을 String Interning 이라고 합니다. 이렇게 String Interning에 저장된 String 값은 불변성(Immutability)을 가지게 됩니다. 불변성을 가진다는 의미는 값은 변함이 없으며 동일한 String 값을 가지고 있다면 같은곳을 가리킨다는 의미입니다.

또한 String Interning은 아래의 흐름으로 값을 찾습니다. 흐름을 보시면 String Pool을 이용하기 때문에 같은 값에 대해서는 새로운 메모리에 할당 없이 재사용 가능하다는 장점을 가지고 있다는 것을 알 수 있습니다.

  1. String의 값이 String Constants Pool에 있는지 찾음
  2. 있다면 바로 반환
  3. 없다면 StringConstants Pool에 해당 값을 할당
  4. 반환

이 흐름을 볼 때 String Interning에 동일한 값이라면 동일한 참조라는 것을 알 수 있습니다. 아래 코드로 테스트를 해보도록 하겠습니다.

@Test
public void stringTest() {
    String literalString1 = "sabarada";
    String literalString2 = "sabarada";

    System.out.println("result = " + literalString1 == literalString2); // result = true
}

String Object

그렇다면 String은 모두 같은 값이라고하면 가리키는 곳도 같을까요 ? 그렇지 않습니다. String Object로 객체의 형태로 String을 생성한다면 각 객체는 다른 메모리를 가리키기 때문에 동일한 값이 나오지 않습니다.

@Test
public void stringTest() {
    String objectString1 = new String("sabarada");
    String objectString2 = new String("sabarada");

    System.out.println("result = " + (objectString1 == objectString2)); // result = false
}

이해하기 쉽게 이미지로 나타내면 아래와 같습니다.

literalString과 objectString이 가리키는 주소

Java 버전에 따른 String Pool의 변화

Java 버전이 업데이트 됨에 따라 많은 변화를 겪었습니다. 먼저 Java 7 이전의 Spring Pool에 대해서 알아보도록 하겠습니다.

Java 6 이전

Java 6 이전에서의 Spring Pool은 사실 Heap 메모리에 존재하지 않았습니다. 바로 PermGen(Permenent Generation)에 있었습니다. 이 PermGen은 메타 클래스 데이터등을 저장해두는 Method 영역에 있는 메모리입니다. 하지만 이 PermGen은 사이즈가 고정(32MB ~ 96MB) 되어있었습니다. 따라서 너무 많은 String 데이터를 사용한다면 OOM이 발생하곤 했습니다. 물론 Java를 실행할 때 -XX:MaxPermSize=N 옵션을 통해서 PermGen의 크기를 늘릴 수 있지만 이또한 고정으로 동적으로 변하지 않습니다.

Java 7

Java 7 버전으로 올라오면서 String Pool은 PermGen이 아닌 Heap 메모리 영역으로 위치를 옮겼습니다. 그렇기 때문에 java 7 부터는 더이상 고정된 String Pool 메모리 사이즈 때문에 걱정하는 일은 없어졌습니다. 이제 Heap 사이즈를 조절하면 String Pool도 함께 영향을 받게 된 것입니다.

Java 8

Java 8이 되면서 고정 크기로 많은 문제를 일으켰던 PermGen은 Metaspace로 이름을 변경하였습니다. 그리고 고정크기에서 동적크기로 메모리 구성이 변경되었습니다.

StringTableSize

Java String Pool은 기본적으로 HashTable 구조를 가지고 있다고 합니다. String을 hashing하고 그것을 key로 하여 값을 찾기 때문에 String Pool은 좋은 성능을 발휘할 수 있다고 합니다. 이 Hash Table의 Bucket의 default 크기는 Java 버전마다 다소 차이가 있습니다. Java 7부터는 1009 이며 Java 11 부터는 60013의 크기를 기본으로 가지고 있습니다.

이 Bucket의 크기 또한 옵션으로 확장가능하며 옵션은 -XX:StringTableSize를 사용하시면 됩니다. interning 된 String을 많이 접근한다고 하면 이 크기를 늘리는 것도 필요할 수 있습니다. 크기는 2의 지수승에서 가까운 소수로 하시면 적절한 성능을 얻을 수 있다고합니다. (java-performance_string-intern-in-java-6-7-8)

마무리

오늘은 Java의 String Pool에 대해서 알아보는 시간을 가져보았습니다.

다음시간에도 좋은내용으로 여러분을 찾아뵙겠습니다.

감사합니다.

참조

baeldung_java-string-pool

java-performance_string-intern-in-java-6-7-8

stackoverflow_how-is-string-pool-measured-in-terms-of-buckets-in-java

댓글