시냅스

무지렁이 개발자의 Out Of Memory Error (XSSF 라이브러리) 정복기 본문

개소리

무지렁이 개발자의 Out Of Memory Error (XSSF 라이브러리) 정복기

ted k 2023. 3. 27. 23:35

https://m.blog.naver.com/hohi47/221619299428

 

무소유란 아무것도 갖지 않는다는 것이 아니라 불필요한 것을 갖지 않는다는 것이다.

비우지 못하면 채우지 못한다던, 시대의 존경을 받았던 법정스님의 말씀이셨습니다.

미련한 중생은 비우는 것에 미련이 남아 OOME 를 발생시켰고

해탈하지 못해 VisualVM 을 통해 꼭 눈으로 확인하였으며

원인을 찾아 성불하게 되는 디지털 서유기입니다...

 

 

https://thewiki.kr/w/%EC%9E%94%20%EC%BF%A0%EA%B3%A0

제어하지 않으면 짐승과도 같습니다.

손오공의 이야기이지만 GC 또한 마찬가지 입니다.

이 괴물같은 녀석은 자기 마음대로 지웠다가 없앴다가 하기 때문입니다...

 

그러니 아래와 같은 기준을 명확히 해야할 것입니다.

 

https://liltdevs.tistory.com/182

 

Java 참조 유형 과 GC (strong, soft, weak, phantom reference)

참조 유형 자바에서는 명시적으로 메모리를 해제할 수 없습니다. 그러한 일들은 GC 가 대리 수행하고 있는데요. https://liltdevs.tistory.com/161 Java 가비지 컬렉션 Garbate Collection 정리 GC stop the world GC를

liltdevs.tistory.com

 

하고자 하는 얘기는 GC 에 긴고아를 씌우자는 당연히 아닙니다...

XSSF 라이브러리의 메모리 로딩 방식에 대한 이야기입니다.

 

 

XSSF, Apache POI

XSSF 는 Excel 을 위한 라이브러리 입니다.

Java 에서 쓰이며, Apache POI 의 하위 라이브러리 입니다.

엑셀 문서 내용을 로드하고 파싱할 때 간편하게 구현할 수 있습니다.

지금 진행하는 프로젝트에서 또한 엑셀 파일을 읽을때 XSSF 를 이용하여 구현하였습니다.

물론, OOME 가 발생하기 이전까지 말입니다.

 

OOME 는 여러 상황에서 발생할 수 있지만, 대체로 Heap Memory가 부족할 때 발생합니다.

때문에 처음 OOME 가 발생했다는 얘기를 들었을 때 우선 Xmx, Xms 설정을 다시 하였고

업로드한 엑셀의 사이즈를 체크하였습니다.

 

클라이언트에서 약 100만개의 행을 가진 엑셀을 업로드하였고

단순 추론으로 기본 Object 32 byte에 +@ 로 개당 1000바이트로 잡더라도

1GB 로 OOME 가 발생한다는 게 이해되지 않았고 간단히 VisualVM 으로 상황을 체크하기로 하였습니다.

 

 

분명히 이상했습니다. 지금봐도 굉장히 기괴합니다.

힙이 치솟고 있고 CPU 사용률이 100%로 올라갈 때도 있었습니다.

당연히 아... GC 가 안되고 있구나 라고 생각하였습니다.

 

 

GC가 전혀 되고 있지 않았습니다.

Strong reference 를 지속적으로 갖고 있거나

저렇게 큰 사이즈를 갖는 Object 가 없었으니 이해할 수 없었습니다...

하여 힙 단면을 확인해보았습니다.

 

 

사이즈를 차지하는 상위 2개의 Object 가

Xobj$ElementXobj

Xobj$AttrXobj 였습니다.

살면서 저런 Object 는 처음 봤고 초면에 굉장히 무례하다고 생각하여

바로 구글에 검색했습니다.

 

https://stackoverflow.com/questions/10721279/poi-outofmemory-exception-with-xlsx-xssf

 

POI OutOfMemory Exception with xlsx (XSSF)

We am trying to use POI 3.8 for an excel component in our application which has to deal with creation of large excel files. I was happy to use SXSSF streaming approach which was fast and very less ...

stackoverflow.com

 

이런 글을 발견할 수 있었습니다.

줄이자면 XSSF 는 엑셀의 모든 내용을 treemap 으로 가지고 메모리에 로딩하여 

대용량 엑셀 파일 처리에서는 OOME 를 발생시킬 가능성이 높다는 것이었습니다.

 

 

SAX (Simple API for XML)

그냥 '아 ㅋㅋ 안되는데요?' 하고 싶었지만...

인생에 쌓아온 양심은 꽤 강한 힘을 가지고 있었습니다...

다시 서치해보니 SAX + XSSF 로 대용량 엑셀 파일을 핸들링하는 게 가능했습니다.

가능한 것은 SAX는 한 줄씩 읽으며 이벤트를 처리할 때 바로 flush 하기 때문이라고 합니다.

 

 

https://howtodoinjava.com/java/library/poi-read-excel-with-sax-parser/

 

Apache POI - Read a Huge Excel File with SAX Parser in Java

Learn to read an excel file containing multiple sheets in Java using the Apache POI and SAX parser, and adding custom event handler functions.

howtodoinjava.com

 

 

위의 글에서 꽤 도움을 얻었습니다.

물론 SAX 를 사용하며, XSSF 보다는 사용성이 떨어져 파싱할 것들이 늘어났지만

저만을 기다릴 클라이언트님들을 생각하며 힘냈습니다...!(ㅋㅋ)

 

 

 

 

테스트 당시의 힙 사용량입니다.

물론 전에 비하면 절반 이하의 수준의 힙 사용량이지만 높은 편이라

리팩토링을 통하여 현재는 1.5GB 이하의 사용량을 보여줍니다.

(깜빡하고 이미지를 못 찍었슴다 ㅎ...)

SAX 를 사용하며 전과 비교하여 낮은 메모리 사용률을 얻어낼 수 있었습니다.

 

소유하는 것이 아니라 풍요롭게 존재하는 것을 목표로 해야 한다던 에리히 프롬의 말을 마지막으로

저는 더 성숙한 코딩 라이프를 즐기도록 하겠습니다...

 

 

 

Comments