2023-java-study / book-study

북 스터디 기록 레포지토리
0 stars 0 forks source link

[item 7] 메모리 누수의 세번째 주범 #19

Closed NuhGnod closed 1 year ago

NuhGnod commented 1 year ago

p. 39 에서 메모리 누수의 세 번째 주범은 바로 리스너 혹은 콜백

Q. 위 리스너 또는 콜백을 사용했을 때 메모리 누수가 일어나는 예시 코드가 궁금합니다

gmelon commented 1 year ago

저도 정확하게는 이해하지 못했지만 예를 들면 아래와 같은 경우인 것 같아요.

WeakReference를 적용하지 않은 콜백 예시

@FunctionalInterface
interface Callback {
    void callbackMethod();
}

class Callee {
    private Callback callback;

    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    private callbackConditional() {
        // 콜백 메서드 호출이 필요한 상황에 호출
        callbackMethod();
    }
}

class Caller {
    private Callee callee;
    private Callback callback = () -> {
        System.out.println("callback method called");
    };

    public Caller() {
        callee.setCallback(callback);
    }
}

위 코드와 같은 상황이면 Callee가 Callback 객체를 계속해서 강한 참조로 들고 있기 때문에 Caller에서 여러 Callee에 Callback을 등록하면 직접 메서드를 통해 해제하지 않는 이상 Caller가 사라져도 (Callee 쪽에서 참조하기 때문에) Callback 객체가 GC 되지 않을 수 있을 것 같습니다.

만약 책에서 말한게 이러한 문제 상황이 맞다면, 아래와 같이 Callee 쪽에서 WeakReference 을 사용해 Caller 가 사라지면 (Callback에 대한 참조가 Callee의 WeakReference만 남으면) Callback 객체가 GC의 대상이 될 수 있도록 할 수 있을 것 같습니다.

WeakReference를 적용한 않은 콜백 예시

@FunctionalInterface
interface Callback {
    void callbackMethod();
}

class Callee {
    private WeakReference<Callback> callback;

    public void setCallback(Callback callback) {
        this.callback = new WeakReference<>(callback);
    }

    private callbackConditional() {
        // 콜백 메서드 호출이 필요한 상황에 호출
        callbackMethod();
    }
}

class Caller {
    private Callee callee;
    private Callback callback = () -> {
        System.out.println("callback method called");
    };

    public Caller() {
        callee.setCallback(callback);
    }
}

참고

http://www.dreamy.pe.kr/zbxe/CodeClip/3768942