> For the complete documentation index, see [llms.txt](https://incheol-jung.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://incheol-jung.gitbook.io/docs/study/effective-java/undefined/2020-03-20-effective-7item.md).

# 아이템7 다 쓴 객체 참조를 해제하라

자바처럼 가비지 컬렉터를 갖춘 언어로 넘어오면 프로그래머의 삶이 훨씬 평안해진다.

그래서 자칫 `메모리 관리에 더 이상 신경 쓰지 않아도 된다고 오해할 수 있는데 절대 사실이 아니다`

```java
    public Class Stack {

        public Object pop() {
            if (size == 0)
                throw new EmptyStackException();
            return elements[--size];
        }
        ...

    }
```

위의 코드는 기본적으로 많이 사용하는 스택 클래스이다.

그런데 이 Stack 클래스를 오래 실행하다 보면 점차 `가비지 컬렉션 활동`과 `메모리 사용량`이 늘어나 결국 성능이 저하될 것이다.

이 코드에서는 스택이 커졌다가 줄어들었을 때 스택에서 꺼내진 객체들을 가비지 컬렉터가 회수하지 않는다. 여기서 다 쓴 참조란 문자 그대로 앞으로 다시 쓰지 않을 참조를 뜻한다. 앞의 코드에서는 elements 배열의 '활성 영역'밖의 참조들이 모두 여기에 해당한다.

객체 참조 하나를 살려두면 가비지 컬렉터는 그 객체뿐 아니라 `그 객체가 참조하는 모든 객체(그리고 또 그 객체들이 참조하는 모든 객체)를 회수해가지 못한다.`

JCF 에서 관리되는 리스트의 필드는 수동으로 메모리를 회수해야 할까?

해법은 간단하다. 해당 참조를 다 썼을 때 null 처리(참조 해제)하면 된다.

```java
    public Object pop() {
        if (size == 0)
                throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // 다 쓴 참조 해제
        return result;    
    }
```

다 쓴 참조를 null 처리하면 다른 이점도 따라온다. 만약 null 처리한 참조를 실수로 사용하려 하면 프로그램은 즉시 `NullPointerException`을 던지며 종료 된다.

하지만 모든 데이터를 사용한 이후에 null 처리할 필요는 없다. 이는 바람직하지도 않고 코드를 지저분하게 만들 뿐이다.

객체 참조를 null 처리하는 일은 `예외적인 경우`여야 한다. 다 쓴 참조를 해제하는 가장 좋은 방법은 `그 참조를 담은 변수를 유효 범위(scope)밖으로 밀어내는 것이다.`

그렇다면 null 처리는 언제 해야 할까? Stack 클래스는 왜 메모리 누수에 취약한 걸까?

`바로 스택이 자기 메모리를 직접 관리하기 때문이다.` 이 스택은 (객체 자체가 아니라 객체 참조를 담는) elements 배열로 저장소 풀을 만들어 원소들을 관리한다.

> 비활성 영역의 객체가 더 이상 쓸모없다는 건 프로그래머만 아는 사실이다. 그러므로 프로그래머는 비활성 영역이 되는 순간 null 처리해서 해당 객체를 더는 쓰지 않을 것임을 가비지 컬렉터에 알려야 한다.

일반적으로 자기 메모리를 직접 관리하는 클래스라면 프로그래머는 항싱 `메모리 누수`에 주의해야 한다.

캐시 역시 메모리 누수를 일으키는 주범이다. 운 좋게 캐시 외부에서 키(Key)를 참조하는 동안만(값이 아니다) 엔트리가 살아 있는 캐시가 필요한 상황이라면 `WeakHashMap`을 사용해 캐시를 만들자

WeakHashMap는 언제 사용할 수 있을까?

LinkedHashMap은 removeEldestEntry 메서드를 써서 후자의 방식으로 처리한다.

메모리 누수의 세 번째 주범은 바로 `리스너 혹은 콜백`이라 부르는 것이다. 클라이언트가 콜백을 등록만 하고 명확히 해지하지 않는다면 뭔가 조치해주지 않는 한 콜백은 계속 쌓여갈 것이다. 이 또한 `WeakHashMap`에 키로 저장하면 해결 가능 하다.

콜백을 등록만 하고 명확히 해지 하지 않는 케이스는 어떤 케이스 일까?

## 정리

메모리 누수는 겉으로 잘 드러나지 않아 시스템에 수년간 잠복하는 사례도 있다. 이런 누수는 철저한 `코드 리뷰`나 `힙 프로파일러` 같은 디버깅 도구를 동원해야만 발견되기도 한다. 그래서 이런 종류의 문제는 예방법을 익혀두는 것이 매우 중요하다.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://incheol-jung.gitbook.io/docs/study/effective-java/undefined/2020-03-20-effective-7item.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
