一个弱引用缓存类
一个在性能优化中经常使用到的WeakReferenceCachePool类。
在优化性能时,经常会使用到缓存类。.NET Framework在System.Web.dll中,提供了一个Cache类。它在Web开发中非常有用,但是如果是WinForm开发,它就用不上了。
在.NET中,由于垃圾回收机制的存在,使得开发人员不用关心内存的分配。不用的对象GC会自动当成垃圾回收。如果能将这些垃圾废品利用的话,很容易节约开销,提升性能。
下面提供一个WeakReferenceCachePool<TKey, TItem>类:
以下是我总结的利用WeakReference做缓存带来的好处和坏处,欢迎拍砖。。。
利用WeakReference做缓存可能带来以下好处:
1,与普通缓存一样,能带来的性能提升
2,不会影响缓存对象被垃圾回收
3,由于是废品利用,可以说不用多占内存,即节约内存
4,由于GC回收机制的存在,能自动处理内存占用与性能间的平衡
5,其他。。。
利用WeakReference做缓存可能带来以下坏处:
1,命中率受GC回收机制影响,不确定
2,其他。。。
另,这篇文章正好是使用WeakReference做缓存的一个例子《一次性能提升300%的优化实践》。
在.NET中,由于垃圾回收机制的存在,使得开发人员不用关心内存的分配。不用的对象GC会自动当成垃圾回收。如果能将这些垃圾废品利用的话,很容易节约开销,提升性能。
下面提供一个WeakReferenceCachePool<TKey, TItem>类:
Code
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
}
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%的优化实践》。
posted on 2009-08-05 15:40 Kevin Shan 阅读(3182) 评论(10) 编辑 收藏 举报