티스토리 뷰

Java

[Java] try-with-resources

snail voyager 2025. 3. 1. 19:45
728x90
반응형

try-with-resources

Java 7에서 도입된 기능으로, 

AutoCloseable 인터페이스를 구현한 리소스를 사용한 후 자동으로 닫아주는 기능을 제공합니다. 

주로 파일, 소켓, 데이터베이스 연결 등과 같은 외부 리소스를 사용할 때 유용합니다.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class MultiResourceExample {
    public static void main(String[] args) {
        try (
            BufferedReader br = new BufferedReader(new FileReader("input.txt"));
            FileWriter fw = new FileWriter("output.txt")
        ) {
            String line;
            while ((line = br.readLine()) != null) {
                fw.write(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • BufferedReader 객체가 try 블록 내에서 선언되었으므로, 블록이 끝나면 자동으로 close()가 호출됩니다.
  • 예외가 발생하더라도 close()가 자동 실행되므로, finally 블록에서 close()를 호출할 필요가 없습니다.

리소스를 close()하지 않으면 발생할 수 있는 문제

메모리 및 리소스 누수 발생

파일 핸들, 소켓, 데이터베이스 커넥션 같은 리소스는 운영체제(OS)에서 관리하는 한정된 자원입니다. 

close()를 호출하지 않으면 이 리소스가 해제되지 않고 계속 점유되어, 

결국 시스템이 리소스를 더 이상 할당할 수 없는 상태(리소스 고갈, Resource Leak) 가 될 수 있습니다.

파일 및 데이터베이스 락(Lock) 문제

파일이나 데이터베이스를 사용하는 경우, 닫지 않으면 다른 프로세스가 해당 리소스에 접근하지 못하는 문제가 발생할 수 있습니다.

데이터베이스 커넥션 부족 문제

데이터베이스를 사용할 때 Connection, Statement, ResultSet 등을 닫지 않으면 커넥션 풀(Connection Pool)이 가득 차서 새로운 연결을 생성할 수 없는 문제가 발생합니다.

많은 사용자가 동시에 접속하는 시스템에서는 DB 서버가 다운되는 문제로 이어질 수 있습니다.

OutOfMemoryError 발생 가능

리소스를 닫지 않으면 GC(Garbage Collector) 가 수거하지 못하는 객체가 늘어나서, 결국 OutOfMemoryError가 발생할 가능성이 있습니다.

파일 핸들이 열려 닫히지 않으므로 운영체제가 허용하는 한계를 초과하여 OutOfMemoryError 또는 Too many open files 오류가 발생할 수 있습니다.

OS 리소스 누수로 인해 서버가 실제로 OOM이 발생할까?

파일 핸들(FD) 누수 → OOM 발생 가능성은 낮지만 장애 위험

파일, 소켓, DB 커넥션 등의 리소스를 close()하지 않으면 운영체제(OS)가 파일 디스크립터(FD)를 계속 점유합니다.

import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class FileHandleLeakExample {
    public static void main(String[] args) throws IOException {
        List<FileReader> readers = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {  // 많은 파일 핸들을 열기
            readers.add(new FileReader("test.txt")); 
        }
    }
}
  • close()를 호출하지 않으므로, OS에서 관리하는 FD(File Descriptor)가 해제되지 않음.
  • 일정 개수를 초과하면 Too many open files 예외 발생.
  • 하지만 Heap 메모리를 사용하지 않으므로 OOM(Java Heap Space) 오류가 발생하지 않음.
  • 대신, 운영체제가 더 이상 파일을 열 수 없게 되어 장애가 발생할 수 있음.

네트워크 소켓 누수 → OS 메모리에 영향 가능

네트워크 소켓을 생성한 후 close()하지 않으면, 커널이 TCP 소켓을 계속 유지하기 때문에 서버의 메모리(RAM)도 점점 증가할 가능성이 있음.

import java.net.Socket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class SocketLeakExample {
    public static void main(String[] args) throws IOException {
        List<Socket> sockets = new ArrayList<>();
        for (int i = 0; i < 100000; i++) {  // 많은 소켓을 열기
            sockets.add(new Socket("example.com", 80));  
        }
    }
}
  • Socket 객체를 생성했지만 close()를 호출하지 않음.
  • OS는 소켓을 계속 유지하면서 네트워크 버퍼를 할당함 → 서버 RAM 사용량 증가 가능.
  • 일정 개수를 초과하면 "Too many open files" 또는 "Address already in use" 오류 발생.
  • 여러 개의 소켓이 메모리를 차지하면서, OS 메모리가 점점 부족해질 수도 있음.

DirectByteBuffer 누수 → OS 메모리에 직접적인 영향

Java의 ByteBuffer.allocateDirect()를 사용하면 Heap이 아니라 OS 메모리(Native Memory) 에 직접 버퍼를 할당합니다. 

하지만 ByteBuffer는 close() 메서드가 없으며, GC가 객체를 수거해야 해제됩니다.

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class DirectMemoryLeakExample {
    public static void main(String[] args) {
        List<ByteBuffer> buffers = new ArrayList<>();
        while (true) {
            buffers.add(ByteBuffer.allocateDirect(10 * 1024 * 1024)); // 10MB씩 할당
        }
    }
}
  • allocateDirect()를 사용하면 OS 메모리에 직접 할당됨 (Heap 메모리가 아님).
  • GC가 ByteBuffer 객체를 정리하지 않으면, 서버 OS 메모리가 점점 부족해짐.
  • 결국 OutOfMemoryError: Direct buffer memory 발생.

파일 핸들(FD) (메모리 영향 없음) ❌ "Too many open files" 오류

DB 커넥션 누수 (메모리 영향 적음) ❌ DB 커넥션 부족

소켓 누수 영향 (네트워크 버퍼 사용 증가) ⚠️ OS 메모리 사용 증가 가능

DirectByteBuffer 누수 (OS 메모리 직접 점유) 🚨 OutOfMemoryError: Direct buffer memory

728x90
반응형

'Java' 카테고리의 다른 글

[Java] Bounded WildCard  (1) 2025.03.03
[Java] Generic  (0) 2025.03.03
[Java] JSON Jackson @JsonProperty  (0) 2025.02.24
[Java] OpenCSV  (0) 2025.01.26
[Java] record  (0) 2025.01.12
반응형
300x250