ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 중복 문자열 제거를 통한 메모리 절약을 위한 -XX:+UseStringDeduplication GC 옵션
    개발 2024. 1. 28. 23:00

    단순한 코딩 보다는 프로세스까지 고려한 코딩이 중요한 것 같습니다.  메모리 절약 코딩 자료를 찾아보던중 잘 정리된 블로그 글을 보고 자주 보기 위해서 제 블로그에 따로 옮겨 적었습니다.

    [ 중복 문자열의 개념과 예시 ]

    중복 문자열이란?

    JDK 개발팀의 조사에 따르면 다음과 같은 자바 애플리케이션의 특징이 있다고 한다.

    • 프로세스의 25%는 문자열임
    • 그 중 13.5%는 중복 문자열임
    • 평균 문자열의 길이는 45자임

     

    중복된 문자열이라 함은 다음과 같이 동일한 내용을 갖지만 별도로 저장된 객체를 의미한다. 둘을 equals로 비교하면 true가 나오지만, ==으로 비교하면 false가 나온다. 이러한 문자열을 우리는 중복 문자열이라고 한다.

    String string1 = new String("MangKyu");
    String string2 = new String("MangKyu");

     

    우리는 중복된 문자열에 의해 평균적으로 13.5%의 메모리를 낭비하고 있는 것이다. 참고로 낭비중인 실제 메모리를 측정하려면 HeapHero와 같은 도구를 사용할 수 있다.

     

    중복 문자열 생성 예시1

    string literal 패턴을 사용하여 public static final String으로 생성하면 메모리를 최적화할 수 있다. 하지만 이를 적용하지 않고 매번 새롭게 만드는 경우가 있다.

    public static final String MANGKYU = "MangKyu";
    
    String string1 = MANGKYU;
    String string2 = MANGKYU;
    

     

    중복 문자열 생성 예시2

    뱅킹/전자상거래 애플리케이션을 구축하는 경우 모든 거래 기록에 대한 통화(예: 'USD', 'EUR', 'INR', ....)를 저장하고 있다고 하자. 모든 거래 레코드에는 통화가 있으므로 애플리케이션은 데이터베이스에서 읽은 모든 거래 레코드에 대해 'USD' 문자열 객체를 생성하게 된다. 이 고객에게 수천 건의 거래가 있는 경우, 이 한 고객을 위해 메모리에 수천 개의 중복된 'USD' 문자열 객체를 생성하는 것이다.

    마찬가지로 애플리케이션이 데이터베이스에서 여러 열(고객 이름, 주소, 주, 국가, 계좌 번호, ID, .....)을 여러 번 읽을 수도 있고, 그 중에는 중복되는 항목이 있을 수 있다. 애플리케이션은 외부 애플리케이션과 함께 JSON과 같은 데이터를 읽고 쓰며, 많은 문자열을 조작한다. 이러한 모든 작업은 중복 문자열을 생성할 수 있다.

    이 문제는 1990년대 중반부터 JDK 팀에서 오랫동안 인식해 왔으며, 지금까지 여러 가지 해결책을 제시해 왔다. 그리고 가장 최근에 추가된 해결책 중 하나가 '- XX:+UseStringDeduplication'이다.

     

    [ -XX:+UseStringDeduplication GC 옵션 ]

    -XX:+UseStringDeduplication JVM 옵션은 중복 문자열을 제거하기 위한 최소한의 노력이라고 볼 수 있다.

    애플리케이션 시작 시 해당 인수를 전달하면, JVM은 가비지 컬렉션 프로세스의 일부로 중복 문자열을 제거하려고 시도한다. 가비지 컬렉션 프로세스 중에 JVM은 메모리의 모든 객체를 검사하므로 이 프로세스의 일부로 객체 중 중복 문자열을 식별하여 제거하려고 시도한다.

    '-XX:+UseStringDeduplication' 옵션만 추가한다고 13.5%의 메모리를 즉시 절약할 수 있는 것은 아니다. 해당 옵션에는 몇 가지 문제점이 있기 때문이다.

    1. G1 GC 알고리즘에서만 적용 가능하다
    2. Long-Lived 객체에만 적용된다
    3. 3번의 GC에서 살아남아야 대상이 되며, StringDeduplicationAgeThreshold 옵션으로 변경 가능하다
    4. GC 일시 중지 시간(Pause Time)에 영향을 줄 수 있다.
    5. 중복 문자열 객체 자체를 제거하는 것이 아니라, 내부의 char[]만 Replace된다.
    6. Java 8 Update 20에서만 적용 가능하다.
    7. XX:+PrintStringDeduplicationStatistics 옵션을 통해 실행에 걸린 시간, 제거된 중복 문자열의 양, 절감된 비용 등의 통계를 볼 수 있다.

     

    해당 옵션을 사용한다고 하여 중복 문자열 객체 자체를 제거하는 것은 아니다. 그저 String 객체 내부의 char[]만 대체할 뿐이다. 따라서 중복 문자열 객체를 제거하는 것은 개념적으로 다음과 같이 값 필드를 재할당하는 것에 불과하다.

    String.value = anotherString.value
    

     

    각 문자열 객체는 최소 24바이트를 차지한다(문자열 객체의 정확한 크기는 JVM 구성에 따라 다르지만 24바이트는 최소값입니다). 따라서 이 기능은 짧은 중복 문자열이 많은 경우 메모리 절약이 덜 할 것이다.

     

    댓글

Designed by Tistory.