2012-01-10 3 views
2

짧은 버전 :

캐시 클래스의 경우 개체가 가비지 수집되었는지 (캐시에서 해당 항목을 제거하기 위해) 알려야합니다. 그렇게하는 가장 좋은 방법은 무엇입니까? 소멸자로부터 이벤트 보내기?개체가 가비지 수집되는 경우 알림을받는 방법?

긴 버전 :

내가 예를 들어, 하나의 큰 매개 변수 트리 객체와 많은 작은 값 유형 매개 변수를 취할 기능을위한 cacher/memoizer을 쓰고,

double myFunc(HugeParTree parTree, int dynPar1, double dynPar2) 

나는 이러한 기능을 캐시 할 다음과 같은 방법으로 : 튜플 (parTree.GUID, dynPar1, dynPar2, ...)

  • Whene에 대한

    • 캐시 결과 ver parTree 변경 사항이 거의 발생하지 않으며 모든 캐시 항목이 삭제됩니다 (Observer 패턴을 통해). (parTree.Equals()은 너무 비싸며 100 개 이상의 값 유형을 비교합니다).

    코드 (하나 개의 값 매개 변수에 대한) 지금이 바로 다음과 같습니다

    public class CachedFunction1ObsPar1Par<TRet, TObsPar1, TPar1> 
         where TObsPar1 : IObservable, IProvideGUID 
        { 
         public delegate TRet ValueCalculator(TObsPar1 obsPar1, TPar1 par1); 
    
         public CachedFunction1ObsPar1Par(ValueCalculator calc) 
         { 
          _calc = calc; 
         } 
    
    
         #region members 
    
         private ValueCalculator _calc; 
    
         private Dictionary<Guid, Dictionary<TPar1, TRet>> _cache = 
          new Dictionary<Guid, Dictionary<TPar1,TRet>>(); 
    
         #endregion 
    
    
         public TRet value(TObsPar1 obsPar1, TPar1 par1) 
         { 
          TRet result; 
          bool cacheHit = checkCache(obsPar1, par1, out result); 
    
          if (cacheHit) 
          { 
           Debug.Assert(result.Equals(_calc(obsPar1, par1))); 
           return result; 
          } 
          else 
          { 
           result = _calc(obsPar1, par1); 
           _cache[obsPar1.GUID].Add(par1, result); 
           return result; 
          } 
         } 
    
         private bool checkCache(TObsPar1 obsPar1, TPar1 par1, out TRet result) 
         { 
          if (!_cache.ContainsKey(obsPar1.GUID)) 
          { 
           _cache.Add(obsPar1.GUID, new Dictionary<TPar1, TRet>()); 
           obsPar1._changed += this.invalidateCache; 
          } 
    
          Dictionary<TPar1, TRet> guidCache = _cache[obsPar1.GUID]; 
    
          bool success = guidCache.TryGetValue(par1, out result); 
    
          return success; 
         } 
    
         private void invalidateCache(object sender) 
         { 
          TObsPar1 obsPar = (TObsPar1)sender; 
    
          _cache.Remove(obsPar.GUID); 
    
          obsPar._changed -= this.invalidateCache; 
         } 
        } 
    

    나는, 아직 테스트하지 않은 나는 아직도 항목이 따라 parTree 후 제거되지는 결코 캐시 문제를 가지고 더 이상 사용되지 않습니다. 아주 오래된 캐시 항목에 대해 반복적 인 "스캔"없이 동기식 솔루션을 좋아할 것입니다.

  • +2

    그러나 캐시에서 참조 된 개체를 유지하면 가비지 수집이 캐시에 도달하지 못합니다. 그것은 바뀌 었습니다 : 먼저 캐시에서 참조를 제거한 다음 오브젝트가 가비지 수집됩니다. – Humberto

    +1

    [가비지 콜렉션 알림] (http://msdn.microsoft.com/en-us/library/cc713687.aspx)에 대한 MSDN의 기사가 유용 할 수 있습니다. –

    +0

    @Humberto 실제로 캐시의 객체에 GUID를 보유하고 있습니다. – B3ret

    답변

    8

    캐시 클래스의 경우 객체가 garbage인지 알려주려면 을 수집해야합니다 (내 캐시에서 해당 항목을 제거함). 가장 좋은 방법은 무엇입니까? 소멸자로부터 이벤트 보내기?

    캐시에 일반 (강력한) 참조가 있으면 항목이 수집되지 않습니다.

    캐시에 WeakReferences가 있으면 아무 것도 제거 할 필요가 없습니다.

    +4

    때때로 죽은'WeakReference'를 제거해야합니다. 그렇지 않으면 그들은 단지 당신의 기억을 가라 앉힐 것이다. – Nuffin

    +0

    실제로 캐시에 객체가 들어 있지 않습니다. Guid를 잡고 있습니다. 나는 Guid-> WeakReference를 보유하려고 생각하고있다. nulled 값으로 GUID를 SortedList하고 제거한다. – B3ret

    +0

    나는 이것을 나의 답을 찾는데 가장 가까운 것으로 대답했다. 나는'SortedList , Guid>를 만들고 때때로 null 참조를 확인할 것입니다. 아래의 소멸자 접근법을 생각해 냈지만 너무 불안정하고 느린 것으로 생각했습니다. – B3ret

    1

    캐시의 개체에 의해 구현되어야하는 인터페이스 'ICacheable'을 정의 할 수 있습니다. 인터페이스 RemoveFromCache()의 메소드에서 캐시의 하위 오브젝트를 검색하여 제거 할 수 있습니다.

    캐시에서 항목을 제거 할 때 해당 인터페이스를 테스트하고 RemoveFromCache()을 호출하십시오.

    이것은 IDisposable과 유사합니다.

    가비지 수집은 실행시기를 알 수 없기 때문에 중요한 요소가 아닙니다.

    1

    헨 크는 이미 요구 사항의 결함을 언급했습니다.

    하지만 질문에 답변 해주세요. 개체가 가비지 수집되는시기를 알기 위해서는 해당 개체에 대한 소멸자를 작성할 수 있습니다.MSDN 당으로

    ~YourClass(); 
    

    :이 GC 또는 소멸자에 의존하는 것이 결코 비록 객체가 액세스

    됩니다 후

    이 메소드는 자동으로 호출된다.

    +1

    정확하지만 dtor은 신뢰할 수없고 b) 비싸다 –

    +0

    나는 면책 조항을 이미 포함했다! 왜 downvote을 가지고 있는지 확실하지 않습니다! –

    관련 문제