에러 상황 : 파일 업로드가 안된다고 함.
웹서버가 올라간 호스트를 보니 디스크(/dev/vda2) 용량이 96%가 차있었음.
일단 데이터를 백업해서 60% 가량으로 떨어트림.
그래도 안된다고 하심.
그래서 문제가 됐다는 파일을 받아서 직접 테스트해보기로 함.
1GB정도의 jpg 파일이었음. (그냥 개발자라 기가단위 넘어가는 이미지 파일은 처음봄.)
올려보니까 다행히도 500 에러가 발생했음. 로그를 확인해볼 수 있게 되어서 보니까
java.lang.OutOfMemoryError: Java heap space
at java.base/java.util.Arrays.copyOf(Arrays.java:3537) ~[na:na]
대충 읽어봐도 힙 공간이 없다고 한다. 그래서 일단 아래 방법을 써봤음.
java -Xmx2g -jar myapp.jar
(JVM 힙 2GB 주라는 옵션 넣어서 빌드해 보기)
spring.servlet.multipart.max-file-size=10GB
spring.servlet.multipart.max-request-size=10GB
(업로드 파일 허용 크기)
(이건 원래 되어있던 설정)
이 방법들을 써봤지만 여전히 같은 오류가 떠서 파일 업로드하는 쪽 코드를 봤는데
long size = multipartFile.getBytes().length;
이런 코드가 있었음. 파일 사이즈를 계산하려고 했던 것 같음.
문제는 getBytes()가 실행되면, 업로드한 파일을 JVM의 바이트 배열에 통째로 올려버림. 배열은 힙 메모리에 올라가고, 그래서 힙 메모리가 터진 것.
long size = multipartFile.getSize();
그래서 아래 코드로 수정함. getSize()는 한꺼번에 파일을 메모리에 올리는 게 아닌, 이미 계산된 Content-Length를 읽어서 그 값만 리턴함.
지금 보니 상당히 기초적인 실수 같은데... 발견하지 못한 건 이 프로젝트를 한 명이 만들었기 때문이겠지... (나아님)
이런 메모리 누수 문제 같은 경우는 여러가지 이유에서 발생할 수 있음.
- String에 루프를 돌면서 += 으로 계속 concat -> StringBuilder() 이용하기
- 매우 큰 JSON에서 ObjectMapper.readValue() 사용
등등... 대용량 파일 처리시에는 메모리도 신경써주자!
'IT > Spring & Spring Boot' 카테고리의 다른 글
| [Spring Boot] 통합 회원관리 시스템(IAM) 구현 기록 (1) | 2025.11.26 |
|---|---|
| [Spring Boot/NGINX] 로그 없는 웹소켓 연결 에러 (3) | 2025.07.08 |
| [IT/일상/Java] MQTT 통신 코드 개선 일지 (feat. QueueChannel, Future) (1) | 2024.12.14 |
| [Spring Boot] RequestBody 필드에 값이 매핑되지 않는 문제 (2) | 2024.11.21 |
| [IT/Spring] 스프링 개념들 복습 (Servlet, MVC, Model, DAO) (1) | 2024.07.21 |