java 코딩 테스트를 준비하시다 보면, 간혹 가다가 메모리 초과를 보는 일이 있습니다. 메모리 제한이 보정되지 않았다면요. 저는 이럴 때, 조금이나마 메모리를 덜 먹는 구조로 바꾸곤 하는데요. 예를 들자면 LinkedList를 ArrayDeque로 바꾼다던지 하는 식입니다. 오늘 설명할 내용은 그것은 아니고, visual VM으로 메모리 사용량을 어떻게 확인하는지 간단하게 알려드리려고 합니다.
당연하게도, 예시는 코테에 치중해서 다루도록 하겠습니다.
먼저, bfs를 구현할 때 많이 쓰는 Queue가 있습니다. 자바에는 Queue는 interface이고요. 그것을 구현한 것이 LinkedList, 즉 리스트 구조와, ArrayDeque, 즉 배열 구조가 있습니다. 사실, 전자보다 후자가 메모리를 조금 덜 먹을 거 같다는 생각을 하실 수 있을 겁니다. 정말 그런지 보도록 하겠습니다.
400만개의 Integer 아이템을 LinkedList에 넣었습니다.
visualVM에서는 Live Byte 수치만 잘 보면 되는데요. LinkedList$Node 객체가 96M, Integer 객체가 64M 차지하고 있음을 알 수 있습니다. 여기서 봐야 할 점은, LinkedList$Node가 상당히 무거운 구조라는 것인데요.
내부를 보면 item과 next, prev가 있습니다. 이 중 item은 실제 들어있는 아이템을 의미합니다. 여기에서는 1, 2, 3과 같은 것들입니다. 이를 그림으로 나타내면 아래와 같습니다.
다음에, Integer는 400만개 있는데요. 이는, ArrayDeque에도 있는 부분이니 생략하도록 하겠습니다. Visual VM에서 본 것은, 노드가 96M만큼 할당되어 있고, Integer가 64M 만큼 할당되어 있습니다. 즉, 이 둘 만으로 160M 정도 할당되었다는 것입니다. Double 링크드 리스트가 가지고 있는 정보가 많기 때문에, 메모리 소모가 많다고 이해하셔도 좋겠습니다.
이제, ArrayDeque를 보겠습니다.
같은 프로그램입니다. 다만, 다른 것은 LinkedList 대신에 ArrayDeque를 썼습니다.
다른 점은 아까와는 다르게, 많이 할당된 부분을 보면 34M, 18M로 96M에 비해서 매우 작다는 것인데요.
크기를 800만으로 늘려 보겠습니다.
그러면, 51M, 11M가 할당되는데요. 여기서 Object[]가 400만에서 800만으로 증가했을 때, 의미있는 증가를 기록했습니다. 따라서, 정수 객체와 Object 배열 객체 2개를 가지고 보는 게 합당할 듯 합니다. 400만일 때 35M, 800만일 때 51.3M. 중요한 것은, 400만일 때 96M나 차지했던 LinkedList와 달랐다는 점입니다.
내부로 들어가 보면 elements만 있는데요. 동적 배열이 있을 거 같은 냄새가 납니다. 확인하는 방법 중에, 제일 괜찮은 방법은, 할당 부분이 있을 거 같은 private 메소드를 보는 것입니다. 2배로 할당하는 내부 동작은 밖에 노출할 리가 없기 때문입니다.
보니까 정말 있네요. doubleCapacity인데요. 꽉 차서 더 이상 할당할 수 없으면 2배로 뻥튀기 하는 메소드입니다.
그림으로 그리면 이런 모습입니다. 이렇게 질문하실 수도 있습니다. 그러면, 확장된 직후에는 LinkedList보다 효율이 떨어지지 않겠냐고 물어보실 수도 있을 겁니다. 2의 제곱수를 넘어갈 때 expand가 되므로, 아이템을 2^22 + 10개 추가하고 메모리를 얼마나 차지하는지 보도록 하겠습니다.
프로그램을 살짝 바꾸었습니다.
51M를 차지합니다. 34M에 비해 꽤 커졌지만, 그래도 95M ~ 96M에 비하면 작다는 것을 알 수 있습니다. 여기서 중요한 것은 Object의 크기가 얼마인지가 아닙니다. 단지, visual VM을 통해서, LinkedList의 Node가 얼마만큼을 차지하는지, 그리고 ArrayDeque가 얼마만큼 차지하는지를 볼 수 있었다는 것입니다.
그래서 자바로 푸시는 분들 중에는 이런 식으로 primitive type으로 직접 구현하시는 것도 좋은 선택입니다. 이 경우에는 어떨까요?
이 때에는 단지, int형을 담는 400만개짜리 배열만 선언하면 됩니다.
뭔가 이것 저것 밑에서 하는 게 많아서 33M가 나오긴 했습니다만, LinkedList나 ArrayDeque에 비해서 메모리 사용량이 상당히 적다는 것을 알 수 있습니다. 간단한 만큼 강력하니, 익혀두시면 코딩 테스트 대비하실 때도 도움이 되실 듯 싶습니다.
'코딩 > Java' 카테고리의 다른 글
java UnsupportedOperationException 예외를 copiesList를 보면서 알아봅시다. (2) | 2021.06.22 |
---|---|
java switch 문 : string에 대해서 어떻게 쓰는지 예제로 알아봅시다. (0) | 2021.06.06 |
java gc log 를 출력해 봅시다. (0) | 2021.03.22 |
java 다른 객체를 참조하는데 ==이 참인 경우가 있을까요? (0) | 2021.03.21 |
java 예외 vs 에러 : 왜 이 둘을 구분 지을까요? (4) | 2021.02.25 |
최근댓글