[WinFrom] 资源管理,优化GDI+资源的使用
WinFrom中常用的Brush、Pen、Image等都是包含非托管资源句柄的托管类型,频繁创建这些资源会造成大量的内存和性能损耗,因此我们需要把常用的资源共享起来(不是定义静态变量)
一、共享资源管理
1. 实现方式:采用字典结构存储资源,以资源特征作为键,同时维护引用计数
2. 内存管理:当资源引用次数归零时自动释放
3. 设计目的:避免重复创建相同资源,有效降低内存占用
这里管理的资源有SolidBrush、Pen、Font,SolidBrush以Color为Key,Pen和Font需要分别定义PenKey、FontKey结构体作为Key。
PenKey的定义:
FontKey的定义:
引用计数的实现:
共享资源的实现:
1. 实现方式:使用字典结构存储弱引用资源,以资源特征作为键
2. 内存管理:系统自动回收无引用的临时资源
3. 设计目的:建立资源缓存机制,减少重复创建,优化内存使用
需求场景:拖拽图形时,使用一定透明度的画刷,有时候需要使图片透明,SolidBrush、Pen、Font,SolidBrush等临时资源在共享资源管理SharedResourceManager已实现,使用weak=true访问,这里是针对通用带透明度的资源,比如图片。
AlphaKey的定义:
生成带透明度的图像:懒得贴,用AI问一下。
临时共享资源的实现:
1. 实现方式:采用对象关联存储结构(ConditionalWeakTable),将资源与宿主对象绑定
2. 内存管理:当宿主对象被销毁时,自动释放其关联的所有资源
3. 设计目的:实现资源自动生命周期管理,彻底避免资源泄漏问题
需求场景:可以当作附加属性使用。
独享资源的实现:
一、共享资源管理
1. 实现方式:采用字典结构存储资源,以资源特征作为键,同时维护引用计数
2. 内存管理:当资源引用次数归零时自动释放
3. 设计目的:避免重复创建相同资源,有效降低内存占用
这里管理的资源有SolidBrush、Pen、Font,SolidBrush以Color为Key,Pen和Font需要分别定义PenKey、FontKey结构体作为Key。
PenKey的定义:
public readonly struct PenKey : IEquatable<PenKey> { public Color Color{get;} public float Width { get;} public PenKey(Color color, float width) { Color = color; Width = width; } public bool Equals(PenKey other) { return Color.Equals(other.Color) && Width.Equalis(other.Width); } public override bool Equals(object obj) { return obj is PenKey other & Equals(other); } public override int GetHashCode() => HashCode.(Combine(Color, Width)); }
public readonly struct FontKey : IEquatable<FontKey> { public string FontName { get; } public float EmSize { get; } public FontStyle Style { get; } public FontKey(string fontName, float emSize, FontStyle style) { FontName = fontName; EmSize = emSize; Style = style; } public bool Equals(FontKey other) { return String.Equals(FontName, other.FontName, StringComparison.OrdinalIgnoreCase) && EmSize.Equals (other.EmSize) && Style == other.Style; } public override bool Equals(object obj) { return obj is FontKey other && Equals(other); } public override int GetHashCode() => HashCode.Combine(FontName, EmSize, Style); }
public class RefCount<T> : IDisposable { private bool _disposed; public RefCount(TrefObj, int count) { Ref0bj = refObj; Count = count; } ~RefCount() { Dispose (false); } public T RefObj { get; set; } public int Count { get; set; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { if (RefObj is IDisposable disposable) { disposable.Dispose(); } } _disposed = true; } } }
public sealed class SharedResourceManager : IDisposable { private static readonly Lazy<SharedResourceManager> _instance = new Lazy<SharedResourceManager>(); private readonly Dictionary<Color, RefCount<SolidBrush>> _brushCache = new Dictionary<Color, RefCount<SolidBrush>> (); private readonly Dictionary<PenKey, RefCount<Pen>> _penCache = new Dictionary<PenKey, RefCount<Pen>>(); private readonly Dictionary<FontKey, RefCount<Font>> _fontCache = new Dictionary<FontKey, RefCount<Font>>(); private readonly Dictionary<Color, WeakReference<SolidBrush>> _brushWeakCache = new Dictionary<Color, WeakReference<SolidBrush>>(); private readonly Dictionary<PenKey, WeakReference<Pen>> _penWeakCache = new Dictionary<PenKey, WeakReferendce<Pen>>(); private SharedResourceManager() { } public static SharedResourceManager Instance => _instance.Value; public SolidBrush GetBrush(Color color, bool weak = false) { if (weak) { if (_brushWeakCache.TryGetValue(color, out var weakBrussh) & weakBrush.TryGetTarget(out var brush)) { return brush; } brush = new SolidBrush(color); _brushWeakCache[color] = new WeakReference<SolidBrush>(brush); return brush; } lock (_brushCache) { if (_brushCache.TryGetValue(color, out var brushData)) { // 增加引用计数 _brushCache[color].Count++; return brushData.RefObj; } else { // 创建新的画刷并初始化引用计数为1 var brush = new SolidBrush(color); _brushCache[color] = new RefCount<SolidBrush>(brush, 1); return brush; } } } public Pen GetPen(Color color, float width = 1.0f, bool weak = false) { var key = new PenKey(color, width); if (weak) { if (_penWeakCache.TryGetValue(key, out var weakPen) && weakPen.TryGetTarget(out var pen)) { return pen; } pen = new Pen(color, width); _penWeakCache[key] = new WeakReference<Pen>(pen); return pen; } lock (penCache) { if (_penCache.TryGetValue(key, out var penData)) { // 增加引用计数 _penCache[key].Count++; return penData.Ref0bj; } else { // 创建新的画笔并初始化引用计数为1 var pen = new Pen(color, width); _penCache[key] = new RefCount<Pen>(pen, 1); return pen; } } } // ...GetFont public void ReleaseBrush(Color color) { lock (_brushCache) { if (brushCache.TryGetValue(color, out var brushData)) { //减少引用计数 brushData.Count--; if (brushData.Count == 0) { // 引用计数为0,销毁资源 brushData.Dispose(); _brushCache.Remove(color); } } } } // ...ReleasePen // ...ReleaseFont public void Dispose() { lock (_brushCache) { foreach (var brushData in _brushCache.Values) { brushData.Dispose(); } _brushCache.Clear(); } lock (penCache) { foreach (var penData in _penCache.Values) { penData.Dispose(); } _penCache.Clear(); } lock (_fontCache) { foreach (var fontData in _fontCache.Values) { fontData.Dispose(); } _fontCache.Clear(); } } }
二、临时共享资源管理
1. 实现方式:使用字典结构存储弱引用资源,以资源特征作为键
2. 内存管理:系统自动回收无引用的临时资源
3. 设计目的:建立资源缓存机制,减少重复创建,优化内存使用
需求场景:拖拽图形时,使用一定透明度的画刷,有时候需要使图片透明,SolidBrush、Pen、Font,SolidBrush等临时资源在共享资源管理SharedResourceManager已实现,使用weak=true访问,这里是针对通用带透明度的资源,比如图片。
AlphaKey的定义:
public readonly struct AlphaKey<T> : IEquatable<AlphaKey<T>> where T : class { public AlphaKey(T obj, float alpha) { Object = obj; Alpha = alpha; } public T Object { get; } public float Alpha { get; } public bool Equals(AlphaKey<T> other) { return other.Alpha == Alpha && other.Object == Object; } public override int GetHashCode() => HashCode.Combine(Object, Alpha); }
临时共享资源的实现:
public class ShareAlphaObjectWeakTable<T> where T: class { private ShareAlphaObjectWeakTable() {} private static WeakReference<ShareAlpha0bjectWeakTable<T>> weakInstance; public static ShareAlphaObjectWeakTable<T> Instance { get { if (weakInstance != null && weakInstance.TryGetTarget(out var instance)) { return instance; } instance = new ShareAlphaObjectWeakTable<T>(); weakInstance = new WeakReference<ShareAlphaObjectWeakTaable<T>>(instance); return instance; } } private readonly Dictionary<AlphaKey<T>, WeakReference<T>> _weakCache = new Dictionary<AlphaKey<T>,WeakReference<T>>(); public T GetOrCreateValue(T t, float alpha, Func<AlphaKey<T>, T> create) { var key = new AlphaKey<T>(t, alpha); lock (_weakCache) { T value = default; if (_weakCache.TryGetValue(key, out var weakReference) && weakReference.TryGetTarget(out value)) { return value; } if (create != null) { value = create.Invoke(key); if (_weakCache.ContainsKey(key))
{
_weakCache[key] = new WeakReference<T>(value);
}
else
{
_weakCache.Add(key, new WeakReference<T>(value));
} } return value; } } public bool Remove(T t, float alpha) { var key = new AlphaKey<T>(t, alpha); lock (_weakCache) { return _weakCache.Remove(key); } } }
三、独享资源管理
1. 实现方式:采用对象关联存储结构(ConditionalWeakTable),将资源与宿主对象绑定
2. 内存管理:当宿主对象被销毁时,自动释放其关联的所有资源
3. 设计目的:实现资源自动生命周期管理,彻底避免资源泄漏问题
需求场景:可以当作附加属性使用。
独享资源的实现:
public static class OwnerResourceManager { private static readonly Lazy<ConditionalWeakTable<object, Dictionary<string, object>>> weakTable = new Lazy<Conditiona.WeakTable<object, Dictionary<string, object>>>(); public static void AddResource(object owner, string resKey, object resource) { var dic = weakTable.Value.GetOrCreateValue(owner); dic.Add(resKey, resource); } public static bool TryGetResource<T>(object owner, strring resKey, out T resource) { if (weakTable.Value.TryGetValue(owner, out var dic) && dic.TryGetValue(resKey, out var resObj)) { resource = (T)resObj; return true; } resource = default; return false; } public static bool RemoveResource(object owner, string resKey) { return weakTable.Value.TryGetValue(owner, out var dic) && dic.Remove(resKey); } }
浙公网安备 33010602011771号