실무/[ 기타 ]

[ 오류 ] 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
반응형