[java] 언제 WeakHashMap 또는 WeakReference를 사용 하시겠습니까?

약한 참조의 사용은 구현을 본 적이없는 것이므로 사용 사례가 무엇인지, 구현이 어떻게 작동하는지 파악하려고합니다. 때 당신은을 사용하는 데 필요한 한 WeakHashMap또는 WeakReference어떻게 사용 되었는가?



답변

강력한 참조의 문제점 중 하나는 캐싱, 특히 이미지와 같은 매우 큰 구조에서 발생합니다. 내가 작업하는 웹 사이트 디자인 도구와 같이 사용자 제공 이미지로 작업해야하는 응용 프로그램이 있다고 가정합니다. 디스크에서 이미지를로드하는 것은 매우 비싸기 때문에 한 번에 두 개의 (잠재적으로 거대한) 이미지 사본이 메모리에있을 가능성을 피하고 싶기 때문에 당연히 이러한 이미지를 캐시하려고합니다.

이미지 캐시는 반드시 필요하지 않을 때 이미지를 다시로드하지 못하도록하기 때문에 캐시에 항상 메모리에있는 모든 이미지에 대한 참조가 포함되어 있어야합니다. 그러나 일반적인 강력한 참조를 사용하면 해당 참조 자체로 이미지가 메모리에 남아있게되므로 이미지가 더 이상 메모리에 더 이상 필요하지 않은 시점을 판별하고 캐시에서 이미지를 제거하여 가비지 콜렉션에 적합하게해야합니다. 가비지 수집기의 동작을 복제하고 객체가 메모리에 있어야하는지 여부를 수동으로 결정해야합니다.

약한 참조 이해 , Ethan Nicholas


답변

WeakReferenceSoftReference

명확하게 구분할 수있는 한 가지 차이점은 a WeakReference와 a 의 차이 SoftReference입니다.

기본적으로 a WeakReference는 참조 된 객체에 대한 하드 참조 가 없으면 JVM에 의해 간절히 GC-d가 됩니다 . 반면에 d 객체는 실제로 메모리를 회수해야 할 때까지 가비지 수집기에 의해 남겨지는 경향이 있습니다.SoftReference

WeakReferences 안에 들어 있는 캐시 는 쓸모가 없습니다 (a WeakHashMap에서는 약하게 참조되는 키입니다). SoftReferences사용 가능한 메모리로 증가 및 축소 할 수있는 캐시를 구현할 때 값을 감싸는 데 유용합니다.


답변

WeakReferences와 WeakHashMaps 의 일반적인 용도 중 하나 는 객체에 속성을 추가하는 것입니다. 경우에 따라 일부 기능이나 데이터를 객체에 추가하려고하지만 하위 클래스 및 / 또는 컴포지션이 옵션이 아닌 경우 추가하려는 속성으로 확장하려는 객체를 연결하는 해시 맵을 만드는 것이 분명합니다. . 그런 다음 속성이 필요할 때마다지도에서 찾을 수 있습니다. 그러나 속성을 추가하는 객체가 많이 파괴되고 생성되는 경향이있는 경우 맵에서 많은 메모리를 차지하는 오래된 객체가 많이 생길 수 있습니다.

WeakHashMap대신에 객체 를 사용하는 경우 객체가 더 이상 프로그램의 나머지 부분에서 더 이상 사용되지 않는 즉시 맵을 떠나게되며 이는 바람직한 동작입니다.

나는 몇 가지 데이터를 추가하기 위해이 작업을 수행했다 java.awt.Component1.4.2과 1.5 사이의 JRE의 변화를 해결하기 위해, 내가 관심 INT (있었다 모든 구성 요소를 서브 클래 싱하여 문제를 해결 한 수 JButton, JFrame, JPanel…) 그러나 이것은 훨씬이었다 훨씬 적은 코드로 쉽게 수행 할 수 있습니다.


답변

또 다른 유용한 경우 WeakHashMapWeakReferenceA는 리스너 레지스트리 구현 .

특정 이벤트를 듣고 싶은 것을 만들 때 일반적으로 리스너를 등록합니다.

manager.registerListener(myListenerImpl);

manager리스너를 리스너에 저장하는 경우 리스너 또는 리스너를 보유한 구성 요소를 사용할 수 없게되면 WeakReference레지스터 manager.removeListener(myListenerImpl)가 자동으로 제거되므로 레지스터를 제거 할 필요 가 없습니다.

물론 리스너를 수동으로 제거 할 수는 있지만 잊어 버렸거나 잊어 버린 경우 메모리 누수가 발생하지 않으며 리스너가 가비지 수집되지 않습니다.

WeakHashMap사진은 어디 에서 나오나요?

등록 된 리스너를 저장하는 리스너 레지스트리 WeakReference에는 이러한 참조를 저장하기위한 콜렉션이 필요합니다. WeakHashSet표준 Java 라이브러리 에는 구현 이 없지만 WeakHashMap후자를 쉽게 사용하여 첫 번째 기능을 “구현”할 수 있습니다.

Set<ListenerType> listenerSet =
    Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());

이를 통해 listenerSet새 리스너를 등록하기 만하면 리스너를 세트에 추가하기 만하면됩니다. 명시 적으로 제거되지 않더라도 리스너가 더 이상 참조되지 않으면 JVM에 의해 자동으로 제거됩니다.


답변

이 블로그 게시물은 Java : ID에서 동기화 두 클래스의 사용법을 보여줍니다 . 사용법은 다음과 같습니다.

private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider();

public void performTask(String resourceId) {
    IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId);
    synchronized (mutext) {
        // look up the resource and do something with it
    }
}

IdMutextProvider는 동기화 할 id 기반 객체를 제공합니다. 요구 사항은 다음과 같습니다.

  • 동등한 ID를 동시에 사용하려면 동일한 객체에 대한 참조를 반환해야합니다.
  • 다른 ID에 대해 다른 객체를 반환해야합니다.
  • 릴리스 메커니즘 없음 (개체가 제공자에게 리턴되지 않음)
  • 누출되지 않아야 함 (사용하지 않은 객체는 가비지 수집 대상 임)

이는 다음 유형의 내부 스토리지 맵을 사용하여 수행됩니다.

WeakHashMap<Mutex, WeakReference<Mutex>>

객체는 키와 가치입니다. 맵 외부에 객체에 대한 하드 참조가없는 경우 가비지 수집 될 수 있습니다. 맵의 값은 하드 참조와 함께 저장되므로 메모리 누수를 방지하기 위해 값을 WeakReference 에 래핑해야합니다 . 이 마지막 요점은 javadoc 에서 다룹니다 .


답변

예를 들어 특정 클래스로 작성된 모든 객체를 추적하려는 경우. 이러한 객체가 가비지 수집되도록하려면 객체 자체 대신 객체에 대한 약한 참조 목록 / 맵을 유지하십시오.

이제 누군가 팬텀 참조를 설명 할 수 있다면 기쁠 것입니다 …


답변

전술 한 바와 같이, 강한 참조가 존재하는 한 약한 참조가 유지된다.

예를 들어 리스너 내부에서 WeakReference를 사용하면 대상 객체에 대한 기본 참조가 없어지면 리스너가 더 이상 활성화되지 않습니다. 이는 WeakReference가 리스너 목록에서 제거됨을 의미하지는 않으며 정리가 여전히 필요하지만 예를 들어 스케줄 된 시간에 수행 될 수 있습니다. 이것은 또한 수신 된 객체가 강력한 참조를 보유하지 못하게하고 결국 메모리 팽창의 원인이되는 것을 방지하는 효과가 있습니다. 예 : 창보다 수명이 더 긴 모델을 참조하는 스윙 GUI 구성 요소.

위에서 설명한 것처럼 청취자를 가지고 놀면서 우리는 객체가 사용자의 관점에서 “즉시”수집된다는 것을 빠르게 깨달았습니다.