본문 바로가기
IT/Spring & Spring Boot

[Java] JVM이 죽었음다 ㅡㅡ; (Java heap space 에러)

by 저당단 2025. 5. 18.
에러 상황 : 파일 업로드가 안된다고 함.

 

 

웹서버가 올라간 호스트를 보니 디스크(/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() 사용

등등... 대용량 파일 처리시에는 메모리도 신경써주자!