이번에 새로 진행하는 신규 프로젝트를 작업중이였는데 모니터링을 하던 도중 의도치 않게 MinorGC 가 자주 발생하고, 시간 또한 긴것을 발견하였다. 그래서 이를 어떻게 개선했는지 그 방법에 대해서 적어보려고 한다.
탐색
일단 Spring Application Proccess 의 번호를 알아야 한다.
jps
프로세스를 알았다면 현재 HeapDump 를 떠서 확인해야 한다. (내 프로세스 번호는 6485번 이였다.)
jmap -dump:format=b,file=heapdump.hprof 6485
잘 dump 가 떠졌다면 아래와 같이 heapdump.hprof 라는 파일을 확인할 수 있을 것이다. 이 파일을 열기 위해서 GC 를 Monitoring 할 수 있는 도구인 VisualVM 을 이용했다. Dump 뜬 파일을 열어보면 아래와 같았다.
GC 를 보면서 느낀건 현재 long[] 과 byte[] 부분의 Instance Size 가 매우 큰것을 확인할 수 있는데 이를 좀 더 정확하게 분석하기 위해서 아래와 같이 GC 가 되는 과정들을 빠르게 dump 를 떠서 분석했다.
이제 내 예측대로 Long 으로 인한 MinorGC 가 자주 일어나고, 대부분이 Long 으로 인한 GC 비용임을 알 수 있었다. 예상했던대로 현재 List 을 처리하는 과정 중에 forEach 를 통해서 과정을 거친 뒤에 해당 Long 들은 필요하지 않게 되는데, 여기서 List 를 사용하는 것이 맞는가 라는 생각이 들었다. 왜냐하면 List 의 원소들을 꺼내어 function 을 거쳐 처리하는 과정인데, 이 과정에서 List 가 옳은가? function 처리 후 기존 object 의 reference 를 List 안에서 유지할 필요가 없기 때문이다.
일단 개선하는데는 좀 시간이 필요할 것 같다. 다음에 개선하는 부분에 대한 글을 적어서 올려보도록 하겠다.
jstat 을 이용한 분석
현재 jstat 을 통해 확인해보면 Eden -> Old 영역으로 가는 양이 많지 않다. 즉, Reference 를 지속적으로 참조하지 않으므로, MinorGC 가 잘 발생하여 계속해서 Eden 영역의 Objcet 를 Collecting 하기 때문이다. 그래서 내가 Null 을 넣어주지 않아도 사실상 GC 는 잘되고 있었던 것이다.
결론
GC 빈도를 줄이려면 Eden 영역을 늘리는 방법이 있겠지만 지금 30초마다의 기록을 봤을때 Eden 영역을 늘리는 것이 빈도를 줄일 수는 있겠지만 큰 도움이 되지 않을것 같았다. FGC 개수가 0인걸 보아 현재 상황에서 Memory leak 현상은 일어나지 않았음을 파악할 수 있었고, 이를 통해 지금 현재 메모리를 잘 이용하고 있다는 생각이 들었다.
지금은 List 를 이용하는데 과연 List 를 사용해야하나? 이런 생각이 들었다. 지금 재사용하고 있지도 않은 상태인데 차라리 그 경우에는 원시값 primitive type Array 를 쓰는게 낫지 않나? 라는 생각이 들었다.
'Kotlin' 카테고리의 다른 글
[EffectiveKotlin-Item02] 변수의 스코프를 최소화 해라 (0) | 2022.05.29 |
---|---|
Effective Kotlin - Item01 (0) | 2022.05.25 |
Kotlin Delegation (0) | 2022.05.16 |
Kotlin Class 내부 object 에서 Class Property 참조하는 법 (0) | 2022.05.11 |
고차함수에서 Return 이 안되는 이유 (1) | 2022.05.03 |