ONE QUESTION AT A TIME.

천천히 생각하고, 분명하게.

TODAY’S QUESTION761 / 1500
언어·런타임난이도 하5분 답변 목표 · 보강본

서로 참조하는 Java 객체가 있는데도 메모리 회수가 가능한가요? GC와 파일·소켓 같은 자원 반납은 어떻게 구분해야 하나요?

잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?

답변과 점검 포인트 펼치기답변 접기
01

구두 답변

정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.

가능합니다. Java 가비지 컬렉션은 참조의 개수를 세어 객체를 지우는 방식으로만 이해하면 안 되고, 살아 있는 스레드가 앞으로의 계산에서 그 객체에 접근할 수 있는지, 즉 도달 가능성(reachability)을 기준으로 회수 대상을 판단합니다. 따라서 다음처럼 두 객체가 서로를 가리켜도 외부에서 그 순환으로 들어갈 참조가 사라지면 둘 다 수집 대상이 될 수 있습니다.

GC root에서의 도달성

아래는 설명용 코드 조각입니다. 타입·메서드 선언과 실행문을 나누어 배치하고, 실행문은 main 등 메서드 안에서 실행합니다.

class Node {
    Node next;
}

Node a = new Node();
Node b = new Node();
a.next = b;
b.next = a;
a = null;
b = null;
// 다른 도달 경로가 없다면 a와 b는 수집 가능

다만 수집 가능하다는 말은 즉시 수집되거나 특정 시점까지 반드시 수집된다는 뜻이 아닙니다. GC는 메모리 객체를 회수하는 런타임 기능이고, 파일 디스크립터·소켓·DB 연결처럼 JVM 힙 밖의 운영체제 자원까지 적시에 닫아 주는 계약은 아닙니다. 더 이상 참조가 없을 때까지 기다리는 방식은 자원 고갈과 지연을 만들 수 있습니다. finalize()에 반납을 맡기는 설명도 최신 Java의 실무 기준으로는 부적절합니다. finalization은 오래전부터 사용이 권장되지 않았고 Java 18부터 제거 예정(deprecated for removal)이며, 실행 시점과 실행 자체를 필요한 정리 작업의 보장으로 삼을 수 없습니다.

힙과 운영체제 자원

자원 소유자가 명확하면 AutoCloseable과 try-with-resources로 사용 범위를 코드에 드러내겠습니다. 블록을 벗어날 때 정상 반환과 예외 경로 모두 close()가 호출되도록 하는 방식입니다. 객체 수명은 GC에 맡기되, 자원 수명은 명시적으로 닫는 두 계약을 분리하는 것이 핵심입니다. 닫기 실패를 로그만 남기고 무시할지, 호출한 작업의 실패로 전파할지는 자원의 성격에 따라 정하되, 메모리 회수가 늦다는 이유만으로 System.gc()를 호출해 자원 반납을 대신하려 하지는 않겠습니다.

선택 기준과 검증

순환이 없어도 static 캐시나 살아 있는 작업 스레드가 GC root 경로를 계속 보유하면 수집되지 않습니다. 반대로 수집 가능한 파일 래퍼가 있다고 해서 파일 디스크립터가 원하는 시점에 닫힌다는 뜻은 아닙니다. try-with-resources의 close() 실패가 주 예외에 suppressed exception으로 붙는 경로까지 확인하고, 힙 덤프와 OS 자원 카운터를 분리해 조사하겠습니다.

강한 참조가 남은 캐시는 정상적인 도달 경로이므로 GC는 그것이 오래됐다는 이유만으로 지우지 않습니다. WeakReference나 SoftReference를 사용하면 수집 정책이 달라질 수 있지만 항목의 보존 시간이나 캐시 용량을 정확하게 제어하는 계약은 아닙니다. 업무상 반드시 필요한 객체를 약한 참조로 바꾸어 메모리 사용량만 낮추면 필요한 상태가 사라질 수 있습니다. 캐시에는 만료·용량·소유권 정책을 먼저 두겠습니다.

try-with-resources는 여러 자원을 선언 역순으로 닫습니다. 본문에서 예외가 났고 close도 실패했다면 일반적으로 본문 예외가 주 예외로 남고 정리 오류가 suppressed exception에 붙으므로 이를 함께 기록해야 합니다. Cleaner는 놓친 정리를 보완할 수 있지만 실행 시점이 확정되지 않는 안전망이지 정상 종료 계약의 대체재가 아닙니다. 힙 객체량, 실제 파일 디스크립터, DB 풀 보유 수를 따로 측정해야 어느 자원이 새는지 알 수 있습니다.

02

득점 포인트

이해가 드러나는 지점을 확인해 보세요.

  • 순환 참조와 GC root 도달 가능성을 구분한다.
  • 수집 가능성·수집 시점·외부 자원 종료를 분리한다.
  • try-with-resources와 힙·native 관측을 사용한다.
03

감점 포인트

놓치기 쉬운 조건과 오해를 짚어 보세요.

  • 서로 참조하는 객체는 참조 수가 남아 영원히 수집되지 않는다고 말한다.
  • GC가 파일·소켓·DB 자원을 적시에 닫는다고 설명한다.
  • System.gc나 finalization을 자원 반납 보장으로 제시한다.
04

더 파고들 거리

하나 더 질문하며 이해의 범위를 넓혀 보세요.

득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.

원리부터 공부하고 싶다면

답변을 보충하는 개념·예제·슈도코드를 읽어 보세요.

← 전체 질문 보기