-
[자바성능] Collection 메모리 최적화 테스트기타 2024. 7. 25. 21:19728x90
회사에서 랜덤 문자열을 생성하는 로직을 작업 중이었다. 이때 생성된 문자열은 DB에는 존재하지 않아야 한다.
해당 로직을 작성중 의문점이 생겼다. 평소에 함수 내에서 사용하지 않는 컬렉션(List, Set...) 변수를
사용이 다 했다면, 해당 변수는 메모리 할당 제거하면 효율성이 더 좋아지지 않을까? 라는 의문점이 생겨서 해당 테스트를 진행했다.
특정 함수 3개를 만들어서 테스트를 진행했다.
동일 조건: 함수 마다 100만 개의String List를 4개 생성한다. 이중 1개만 반환하도록 한다.
1번째 함수: 반환하지 않는 함수들의 메모리 할당을 제거하지 않는다.
2번째 함수: 반환하지 않는 함수들을 clear()한다. (컬렉션에 속해있는 변수들 제거)
3번째 함수: 반환하지 않는 함수들을 null값으로 반환한다.
위의 조건을 만족하는 테스트코드는 아래와 같다.
class MomoryTest { private final int size = 1_000_000; // JVM의 현재 Runtime 인스턴스 얻기 Runtime runtime = Runtime.getRuntime(); @Test void collectionSetTest() throws InterruptedException { runtime.gc(); Thread.sleep(1000); // 초기 메모리 사용량 출력 System.out.println("==========================="); // 초기 메모리 사용량 출력 printMemoryUsage("Initial"); List<String> strings = notResetList(); // 초기 메모리 사용량 출력 printMemoryUsage("notResetList"); strings.clear(); // 컬렉션 비운 후 메모리 사용량 출력 printMemoryUsage("After clearing elements"); // 가비지 컬렉션 실행 요청 runtime.gc(); // 가비지 컬렉션 후 메모리 사용량 출력 printMemoryUsage("After GC"); System.out.println("==========================="); } @Test void collectionSetTest2() throws InterruptedException { System.out.println("==========================="); runtime.gc(); Thread.sleep(1000); // 초기 메모리 사용량 출력 // 초기 메모리 사용량 출력 printMemoryUsage("Initial"); List<String> strings = resetList(); // 초기 메모리 사용량 출력 printMemoryUsage("resetList"); strings.clear(); // 컬렉션 비운 후 메모리 사용량 출력 printMemoryUsage("After clearing elements"); // 가비지 컬렉션 실행 요청 runtime.gc(); // 가비지 컬렉션 후 메모리 사용량 출력 printMemoryUsage("After GC"); System.out.println("==========================="); } @Test void collectionSetTest3() throws InterruptedException { System.out.println("==========================="); runtime.gc(); Thread.sleep(1000); // 초기 메모리 사용량 출력 printMemoryUsage("Initial"); List<String> strings = clearList(); // 초기 메모리 사용량 출력 printMemoryUsage("clearList"); strings.clear(); // 컬렉션 비운 후 메모리 사용량 출력 printMemoryUsage("After clearing elements"); // 가비지 컬렉션 실행 요청 runtime.gc(); // 가비지 컬렉션 후 메모리 사용량 출력 printMemoryUsage("After GC"); System.out.println("==========================="); } public List<String> notResetList() { List<String> result = new ArrayList<>(); List<String> result1 = new ArrayList<>(); List<String> result2 = new ArrayList<>(); List<String> result3 = new ArrayList<>(); for (int i = 0; i < size; i++) { result.add(String.valueOf(i)); result1.add(String.valueOf(i)); result2.add(String.valueOf(i)); result3.add(String.valueOf(i)); } return result; } public List<String> resetList() { List<String> result = new ArrayList<>(); List<String> result4 = new ArrayList<>(); List<String> result5 = new ArrayList<>(); List<String> result6 = new ArrayList<>(); for (int i = 0; i < size; i++) { result.add(String.valueOf(i)); result4.add(String.valueOf(i)); result5.add(String.valueOf(i)); result6.add(String.valueOf(i)); } result4 = null; result5 = null; result6 = null; return result; } public List<String> clearList() { List<String> result = new ArrayList<>(); List<String> result4 = new ArrayList<>(); List<String> result5 = new ArrayList<>(); List<String> result6 = new ArrayList<>(); for (int i = 0; i < size; i++) { result.add(String.valueOf(i)); result4.add(String.valueOf(i)); result5.add(String.valueOf(i)); result6.add(String.valueOf(i)); } result4.clear(); result5.clear(); result6.clear(); return result; } private static void printMemoryUsage(String phase) { Runtime runtime = Runtime.getRuntime(); long usedMemory = runtime.totalMemory() - runtime.freeMemory(); System.out.println(phase + " memory usage: " + usedMemory / (1024 * 1024) + " MB"); } }
해당 테스트를 진행한 결과 확실히 사용하지 않는 컬렉션을 초기화 하니 메모리 소비를 덜한다는 결론이 나왔다.
String 객체 100만개 기준 약 10mb를 절약할 수 있는 것으로 보였다. 신기한 것은
반환된 컬렉션을 clear을 했을 때 차이점이 보였다는 것이다. 아직 어떤 원인 때문인지는 파악을 못했다..
추측해보자면 "함수내에서 생성된 List들이 반환되지 않은건 아닐까?" 라는 생각이 든다.더 깊은 고민을 해봐야 하는 것은, 실제 엔티티같이 필드가 많은 클래스들을 갖고 테스트를 하면 얼마나 메모리 소비량이 차이날지
테스트를 해봐야 할 것 같다.이 테스트로써 알게된 것은 지역변수를 사용한 뒤, 할당제거를 한다면 메모리에 이점이 있다는것을 알 수 있었다..
=========================== Initial memory usage: 7 MB notResetList memory usage: 259 MB After clearing elements memory usage: 260 MB After GC memory usage: 7 MB =========================== =========================== Initial memory usage: 3 MB resetList memory usage: 235 MB After clearing elements memory usage: 236 MB After GC memory usage: 7 MB =========================== =========================== Initial memory usage: 2 MB clearList memory usage: 235 MB After clearing elements memory usage: 236 MB After GC memory usage: 7 MB ===========================
728x90'기타' 카테고리의 다른 글
[자바 성능]자바 리플랙션을 이용하여 Redis Hash 데이터 구조 삽입 (0) 2024.07.31 [MAC] qemu-system-aarch64 메모리 과다 사용 현상 (0) 2024.06.04 [패스트캠퍼스 온라인강의] The RED 비즈니스 성공을 위한 MSA 구축 후기 (0) 2023.12.13 스프링7주차 회고록 (0) 2023.04.25 코드숨 스프링 6주차 (1) 2023.04.18