[WinFrom] 资源管理,优化GDI+资源的使用

WinFrom中常用的Brush、Pen、Image等都是包含非托管资源句柄的托管类型,频繁创建这些资源会造成大量的内存和性能损耗,因此我们需要把常用的资源共享起来(不是定义静态变量)
一、共享资源管理
    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));
}
FontKey的定义:
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);
}
生成带透明度的图像:懒得贴,用AI问一下。
临时共享资源的实现:
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);
    }
}

 

posted @ 2025-09-01 16:45  孤独成派  阅读(19)  评论(0)    收藏  举报