首页 > 代码库 > 转 一个弱引用缓存类

转 一个弱引用缓存类

  在优化性能时,经常会使用到缓存类。.NET Framework在System.Web.dll中,提供了一个Cache类。它在Web开发中非常有用,但是如果是WinForm开发,它就用不上了。
  在.NET中,由于垃圾回收机制的存在,使得开发人员不用关心内存的分配。不用的对象GC会自动当成垃圾回收。如果能将这些垃圾废品利用的话,很容易节约开销,提升性能。
下面提供一个WeakReferenceCachePool<TKey, TItem>类:

技术分享
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.ConstrainedExecution;

namespace CacheDemo
{
    #region The WeakReferenceCachePool<TKey, TItem> class

    public class WeakReferenceCachePool<TKey, TItem> where TItem : class
    {
        #region The Cleaner class

        private class Cleaner : CriticalFinalizerObject
        {
            #region Instance Data

            private WeakReferenceCachePool<TKey, TItem> _owner;

            #endregion

            #region Constructor & Finalizer

            public Cleaner(WeakReferenceCachePool<TKey, TItem> owner)
            {
                this._owner = owner;
            }

            ~Cleaner()
            {
                if (this._owner._autoCleanAbandonedItems)
                {
                    this._owner.CleanAbandonedItems();
                    GC.ReRegisterForFinalize(this);
                }
            }

            #endregion
        }

        #endregion

        #region Instance Data

        private const int LOCK_TIMEOUT_MSECS = 500;
        private Dictionary<TKey, WeakReference> _cachePool;
        private bool _autoCleanAbandonedItems;
        private ReaderWriterLockSlim _cacheLock;

        #endregion

        #region Constructor & Finalizer

        public WeakReferenceCachePool() : this(true) { }

        public WeakReferenceCachePool(bool autoCleanAbandonedItems)
        {
            this._cacheLock = new ReaderWriterLockSlim();
            this._cachePool = new Dictionary<TKey, WeakReference>();
            this._autoCleanAbandonedItems = autoCleanAbandonedItems;
            if (this._autoCleanAbandonedItems)
            {
                new Cleaner(this);
            }
            else
            {
                GC.SuppressFinalize(this);
            }
        }

        ~WeakReferenceCachePool()
        {
            this._autoCleanAbandonedItems = false;
        }

        #endregion

        #region Properties

        public bool AutoCleanAbandonedItems
        {
            get
            {
                return this._autoCleanAbandonedItems;
            }
        }

        public TItem this[TKey key]
        {
            get
            {
                if (key == null)
                {
                    throw new ArgumentNullException("key");
                }

                if (this._cacheLock.TryEnterReadLock(LOCK_TIMEOUT_MSECS))
                {
                    try
                    {
                        WeakReference weakReference;
                        if (_cachePool.TryGetValue(key, out weakReference))
                        {
                            return (TItem)weakReference.Target;
                        }
                    }
                    finally
                    {
                        this._cacheLock.ExitReadLock();
                    }
                }

                return null;
            }
            set
            {
                this.Add(key, value);
            }
        }

        #endregion

        #region Methods

        public void Add(TKey key, TItem item)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            if (this._cacheLock.TryEnterWriteLock(LOCK_TIMEOUT_MSECS))
            {
                try
                {
                    _cachePool[key] = new WeakReference(item);
                }
                finally
                {
                    this._cacheLock.ExitWriteLock();
                }
            }
        }

        public void Remove(TKey key)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            if (this._cacheLock.TryEnterWriteLock(LOCK_TIMEOUT_MSECS))
            {
                try
                {
                    this._cachePool.Remove(key);
                }
                finally
                {
                    this._cacheLock.ExitWriteLock();
                }
            }
        }

        public void Clear()
        {
            if (this._cacheLock.TryEnterWriteLock(LOCK_TIMEOUT_MSECS))
            {
                try
                {
                    this._cachePool.Clear();
                }
                finally
                {
                    this._cacheLock.ExitWriteLock();
                }
            }
        }

        public void CleanAbandonedItems()
        {
            if (this._cacheLock.TryEnterWriteLock(LOCK_TIMEOUT_MSECS))
            {
                try
                {
                    Dictionary<TKey, WeakReference> newCachePool = new Dictionary<TKey, WeakReference>();
                    foreach (KeyValuePair<TKey, WeakReference> keyValuePair in _cachePool)
                    {
                        if (keyValuePair.Value.IsAlive)
                        {
                            newCachePool[keyValuePair.Key] = keyValuePair.Value;
                        }
                    }

                    this._cachePool = newCachePool;
                }
                finally
                {
                    this._cacheLock.ExitWriteLock();
                }
            }
        }

        #endregion
    }

    #endregion
}



  以下是我总结的利用WeakReference做缓存带来的好处和坏处,欢迎拍砖。。。

  利用WeakReference做缓存可能带来以下好处:
  1,与普通缓存一样,能带来的性能提升
  2,不会影响缓存对象被垃圾回收
  3,由于是废品利用,可以说不用多占内存,即节约内存
  4,由于GC回收机制的存在,能自动处理内存占用与性能间的平衡
  5,其他。。。

  利用WeakReference做缓存可能带来以下坏处:
  1,命中率受GC回收机制影响,不确定
  2,其他。。。

另,这篇文章正好是使用WeakReference做缓存的一个例子《一次性能提升300%的优化实践》。

小Tip:
可以适当地使用 GC.KeepAlive(cachedObject)来避免cachedObject 被GC回收。

-------------
p.s.
cachedObject 就是被WeakReference track 的那个,比如:
WeakReference wf = new WeakReference(cachedObject);

 

转 一个弱引用缓存类