HihoBookStudy / EffectiveJava

이펙티브 자바 북스터디입니다.
1 stars 0 forks source link

[아이템 7] 콜백함수의 메모리 누수를 해결하기 위한 WeakHashMap #11

Closed zpqmdh closed 3 months ago

zpqmdh commented 3 months ago

자바에는 세 가지 참조 유형이 있다고 합니다.

image

출처: https://blog.breakingthat.com/2018/08/26/java-collection-map-weakhashmap/

아이템 7 39페이지 내용에 따르면, 메모리 누수의 세 번째 주범은 콜백을 등록만 하고 명확히 해지하지 않았을 때입니다. 이때, 약한 참조로 저장하면 GC가 즉시 수거해간다고 하는데 콜백을 WeakHashMap 으로 저장한다는게 와닿지 않아서 그런데 간단한 예시를 들어주실 수 있나요?

ForteEscape commented 3 months ago

Q.

약한 참조로 저장하면 GC가 즉시 수거해간다고 하는데 콜백을 WeakHashMap 으로 저장한다는게 와닿지 않아서 그런 데 간단한 예시를 들어주실 수 있나요?

A.

WeakHashMap - Java 8 SE document

다음과 같은 예시를 봅시다.

public  class CallBackTest {

    @FunctionalInterface
    public interface Callback {
        public void method();
    }

    public static void main(String[] args) {
        Object obj = new Object();
        Map<Object, Callback> weakHashMap = new WeakHashMap<>();

        CallBackTest.Callback callback = new CallBackTest.Callback() {
            @Override
            public void method() {
                 // do something...
            }
        }

        // obj를 key로 하여 WeakedHashMap에 저장합니다.
        // 이때 Key가 되는 obj는 약한 참조로 설정되어 저장됩니다.
        weakHashMap.put(obj, callback);

        obj = null;

        // GC에 의해 콜백 함수가 해당 Entry를 회수할 때 까지 대기합니다.
        while(true) {
            System.gc();
            if(weakHashMap.size() == 0) {
                break;
            }
        }
    }
}
ForteEscape commented 3 months ago

약한 참조(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);
    }
}
zpqmdh commented 3 months ago

참조 유형에 대해 이번에 알게 되었는데, 들어주신 예시 덕분에 각 유형의 차이를 더 쉽게 이해할 수 있게 되었어요!! 감사합니다 :)