실무/[ 기타 ]
[ 오류 ] java.lang.OutOfMemoryError: Java heap space (MIME 관련)
glenn93
2024. 9. 25. 16:25
728x90
반응형
상황
웹에서 고객이 대용량 동영상 파일을 첨부하는도중 오류가 발생했다.
로그 확인
org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space
..
..
..
Caused by: java.lang.OutOfMemoryError: Java heap space
at java.lang.String.toCharArray(String.java:2748)
at org.apache.oro.text.perl.Perl5Util.match(Unknown Source)
at net.sf.jmimemagic.MagicMatcher.testRegex(MagicMatcher.java:676)
at net.sf.jmimemagic.MagicMatcher.testInternal(MagicMatcher.java:446)
at net.sf.jmimemagic.MagicMatcher.test(MagicMatcher.java:240)
at net.sf.jmimemagic.Magic.getMagicMatch(Magic.java:344)
at net.sf.jmimemagic.Magic.getMagicMatch(Magic.java:240)
에러 발생 원인
OutOfMemoryError 는 말그대로 메모리 부족문제가 원인이다. jvm에 할당된 메모리 사이즈보다 큰 작업을 수행하기에 발생하는 것이다.
해결 방법
- JVM메모리 증가 : -Xmx512m > -Xmx2048m
- 스트리밍 처리로 전환 : 파일 업/다운로드 시 메모리로 한번에 로드하지않고 스트리밍 방식으로 처리
MultipartFile.transferTo() 처럼 파일을 메모리로 한 번에 로드하는 대신 스트리밍 방식으로 처리하여 메모리 사용을 줄일 수 있다. Spring에서 제공하는 InputStream을 사용해 파일을 직접 처리하는 방식으로 전환을 고려 - 파일 크기 제한 : 가장 원초적인 방법으로, 지나친 대용량 파일을 업로드 못하게 설정. Spring에서는 MultipartResolver를 사용해 최대 파일 크기를 설정
- MIME 타입 체크 최적화: 나의 경우 업로드한 동영상 파일의 MiME 타입 확인 시 사용하는 net.sf.jmimemagi라이브러리는 메모리에 파일을 올려서 처리하는 방식이므로 메모리 사용량이 컸다. 따라서 Apache Tika를 사용하여 파일의 일부부만 확인하는 스트리밍 방식으로 메모리 오버현상을 방지하였다.
1. 파일 크기제한 예제
# context-core.xml의 maxInMemorySize 속성을 작은 값으로 설정해 큰 파일은 메모리가 아닌 디스크에 임시 저장하도록 설정
# 현재 <property name="maxInMemorySize" value="500000000" />라고 지정되어 잇음.
# 476.8 MB까지 메모리에 저장가능하며. 이 값을 초과하는 파일은 메모리가 아닌 임시 디스크 공간에 자동 저장됨.
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 업로드 파일 최대 크기 -->
<property name="maxUploadSize" value="500000000" />
<!-- 메모리에 저장할 수 있는 최대 크기 -->
<property name="maxInMemorySize" value="1000000" />
<!-- 업로드된 파일을 저장할 디렉토리 (절대 경로) -->
<property name="uploadTempDir" value="/custom/upload/temp/dir" />
</bean>
2. MIME 타입 체크 최적화 예제
// 최초 maven의존성 추가 하기
// pom.xml
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>2.7.0</version>
</dependency>
// FileServiceImpl.java
..
..
File uploadFile = new File(uploadFullPath, uploadFileName);
String mimeType = FileUtils.getMimeTypeByTika(uploadFile);
..
..
..
// FileUtils.java
public static String getMimeType(File file) {
String mimeType = null;
try {
MagicMatch match = Magic.getMagicMatch(file, false);
if (match != null) {
mimeType = match.getMimeType();
}
} catch (Exception e) {
log.debug(e.getMessage());
}
return mimeType;
}
// 위 소스를 apache Tika로 수정 ---------------------------------------------
public static String getMimeType(File file) throws IOException {
Tika tika = new Tika();
return tika.detect(file);
}
728x90
반응형