티스토리 뷰
[Java] 중복 문자열 제거를 통한 메모리 절약을 위한 -XX:+UseStringDeduplication GC 옵션
망나니개발자 2024. 1. 23. 10:00아래의 내용은 DZone의 포스팅을 바탕으로 참고하여 정리한 내용입니다.
1. 중복 문자열 제거를 통한 메모리 절약을 위한
-XX:+UseStringDeduplication GC 옵션
[ 중복 문자열의 개념과 예시 ]
중복 문자열이란?
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%의 메모리를 즉시 절약할 수 있는 것은 아니다. 해당 옵션에는 몇 가지 문제점이 있기 때문이다.
- G1 GC 알고리즘에서만 적용 가능하다
- Long-Lived 객체에만 적용된다
- 3번의 GC에서 살아남아야 대상이 되며, StringDeduplicationAgeThreshold 옵션으로 변경 가능하다
- GC 일시 중지 시간(Pause Time)에 영향을 줄 수 있다.
- 중복 문자열 객체 자체를 제거하는 것이 아니라, 내부의 char[]만 Replace된다.
- Java 8 Update 20에서만 적용 가능하다.
- XX:+PrintStringDeduplicationStatistics 옵션을 통해 실행에 걸린 시간, 제거된 중복 문자열의 양, 절감된 비용 등의 통계를 볼 수 있다.
해당 옵션을 사용한다고 하여 중복 문자열 객체 자체를 제거하는 것은 아니다. 그저 String 객체 내부의 char[]만 대체할 뿐이다. 따라서 중복 문자열 객체를 제거하는 것은 개념적으로 다음과 같이 값 필드를 재할당하는 것에 불과하다.
String.value = anotherString.value
각 문자열 객체는 최소 24바이트를 차지한다(문자열 객체의 정확한 크기는 JVM 구성에 따라 다르지만 24바이트는 최소값입니다). 따라서 이 기능은 짧은 중복 문자열이 많은 경우 메모리 절약이 덜 할 것이다.
아래의 내용은 DZone의 포스팅을 바탕으로 참고하여 정리한 내용입니다.
'Java & Kotlin' 카테고리의 다른 글
[Java] 스레드 로컬(ThreadLocal)과 상속 가능한 스레드 로컬( InheritableThreadLocal)에 대하여 (2) | 2024.02.06 |
---|---|
[Java] Nested Class(중첩 클래스)에 대한 자바 스펙 문서 정리 (0) | 2024.01.30 |
[Java] 기존 동시성 프로그래밍의 한계와 새롭게 도입될 구조적 동시성(Structured Concurrency) (0) | 2024.01.16 |
[Java] 자바는 Call By Value(Pass By Value) 방식으로만 동작한다 (12) | 2024.01.09 |
[Java] 언제 추상 클래스(Abstract Class) 또는 인터페이스(Interface)를 사용해야 하는가? (2) | 2023.12.19 |