-
Java에서 Files.copy 등을 하면 파일 크기만큼 어플리케이션 메모리가 늘어날까?JAVA 2021. 6. 20. 23:44
파일을 복사하는 과정에서 일시적으로 파일 크기만큼 메모리를 사용한다고 생각할 수 있다. 그러면 파일이 큰 경우, 충분한 메모리가 없다면 메모리 부족 문제가 발생할 수 있을 것이다. 이를 방지하기 위해 스트림을 사용하여 파일을 읽고 쓰는 방식으로 메모리 사용량을 최소화할 수 있는 방식을 사용한다. 예를 들어, 아래와 같이 파일 스트림을 사용하여 파일을 복사하면 메모리 사용량을 줄일 수 있다.
public class FileCopyExample { public static void copyFile(Path source, Path target) throws IOException { try (InputStream in = Files.newInputStream(source); OutputStream out = Files.newOutputStream(target)) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = in.read(buffer)) != -1) { out.write(buffer, 0, bytesRead); } } }
위의 예제에서는 8192 바이트 크기의 버퍼를 사용하여 파일을 읽고 쓰기 때문에 메모리 사용량을 보다 효율적으로 관리할 수 있다. Files.copy를 사용할 때보다 메모리 사용량이 적어지며, 큰 파일을 처리할 때 유용하다.
이 코드는 다음과 같은 방식으로 작동한다.
- InputStream과 OutputStream을 생성: 소스 파일과 타겟 파일에 대해 각각의 스트림을 생성한다.
- 버퍼를 사용하여 읽고 쓰기: 8192 바이트 크기의 버퍼를 생성하고, in.read(buffer) 메서드를 사용하여 파일을 읽는다. 읽은 바이트 수를 반환받아 out.write(buffer, 0, bytesRead)를 통해 타겟 파일에 쓴다.
- 반복: 파일의 끝까지 읽고 쓸 때까지 이 과정을 반복한다.
- 스트림 닫기: try-with-resources 구문을 사용하여 스트림이 자동으로 닫히도록 한다.
이 방법을 사용하면 메모리 사용량이 버퍼 크기만큼만 증가하므로 큰 파일을 처리할 때 메모리 효율성을 높일 수 있다.
Spring, Kotlin 예)
UrlResource(httpUrl).inputStream.use { inputStream -> Files.copy( inputStream, Paths.get(fileName).toAbsolutePath(), StandardCopyOption.REPLACE_EXISTING ) }
이 예제는 Files.copy 메서드를 사용하여 파일을 복사할 때, 내부적으로 버퍼를 사용하므로 파일 전체를 메모리에 로드하지 않는다. 이는 파일의 크기가 크더라도 메모리 사용량이 버퍼 크기만큼으로 제한된다는 것을 의미한다.
해당 예제는 UrlResource를 사용하여 HTTP URL에서 파일을 다운로드하고, Files.copy 메서드를 사용하여 로컬 파일 시스템에 저장하는 코드이다. 이 코드는 내부적으로 버퍼를 사용하므로 메모리 사용량이 효율적으로 관리된다.
이 코드에서 Files.copy 메서드는 내부적으로 버퍼를 사용하여 입력 스트림에서 데이터를 읽고 파일에 쓰게된다. 따라서 파일 크기가 매우 크더라도 메모리 사용량은 버퍼 크기만큼만 증가한다.
Files.copy의 동작 방식
Files.copy 메서드는 내부적으로 버퍼 크기를 조절하여 파일을 복사한다. 기본적으로 자바 NIO는 BufferedInputStream과 BufferedOutputStream을 사용하여 데이터를 읽고 쓰며, 버퍼 크기는 일반적으로 8192 바이트이다. 이 크기는 충분히 효율적이지만, 필요에 따라 직접 스트림을 사용하여 버퍼 크기를 조절할 수도 있다. 필요에 따라 버퍼 크기를 직접 지정하고 싶다면, 다음과 같이 BufferedInputStream과 BufferedOutputStream을 사용할 수 있다.