Кэширование объектов GDI + в приложении winforms: стоит ли это и как это сделать правильно? - PullRequest
10 голосов
/ 15 февраля 2012

Для некоторых моих приложений winforms мне нужно создать целую кучу объектов GDI + (кисти, ручки, шрифты и т. Д.) И использовать их снова и снова. Я создал гетто кеширующий синглтон, чтобы выполнить то, что мне нужно, но запах кода подавляющий ...

public sealed class GraphicsPalette
{
    public static readonly GraphicsPalette Instance = new GraphicsPalette();

    static GraphicsPalette()
    {
    }

    private Dictionary<Color, Brush> solidBrushes;

    //multithreading
    private object brushLock;

    private GraphicsPalette()
    {
        solidBrushes = new Dictionary<Color, Brush>();

        brushLock = new object();
    }

    public Brush GetSolidBrush(Color color, int alpha)
    {
        return GetSolidBrush(Color.FromArgb(alpha, color));
    }

    public Brush GetSolidBrush(Color color)
    {
        if (!solidBrushes.ContainsKey(color))
        {
            lock (brushLock)
            {
                if (!solidBrushes.ContainsKey(color))
                {
                    Brush brush = new SolidBrush(color);
                    solidBrushes.Add(color, brush);
                    return brush;
                }
            }
        }
        return solidBrushes[color];
    }
}
  1. Есть ли лучший способ для меня повторно использовать эти объекты GDI +, в отличие от их повторного создания каждый раз при вызове OnPaint() и т. Д.?
  2. Будут ли объекты GDI + вызывать неуправляемую утечку памяти после завершения программы, или будет вызван финализатор для каждого Brush объекта, который, в свою очередь, освободит любые неуправляемые ресурсы?

Я прошу прощения, если это повторение, но я не нашел подобных вопросов.

Ответы [ 2 ]

5 голосов
/ 20 февраля 2012

Не будет утечки памяти, но лучше выпускать объекты GDI +, когда это имеет смысл для вас.Их количество в операционной системе ограничено, поэтому вы можете вызвать проблемы с рендерингом в ваших и других приложениях.Следует также упомянуть, что объекты GDI + (шрифты и т. Д.) Не могут одновременно использоваться потоками 2+ (могут возникнуть некоторые трудные для воспроизведения исключения).Вас могут заинтересовать некоторые измерения фактического времени создания объектов GDI + в зависимости от возможных исключительных задержек блокировки.«преждевременная оптимизация - корень всего зла» © Дональд Кнут

На самом деле для меня работает кэширование некоторых объектов GDI +: за цикл рисования.Код клиента может выглядеть следующим образом:

class Visual 
{
    public void Draw() 
    {
        using (new GraphicsPalette()) {
            DrawHeader();
            DrawFooter();
        }
    }

    private void DrawHeader() {
        var brush = GraphicsPalette.GetSolidBrush(Color.Green);
        ...   
    }

    public void DrawFooter() { 
        using (new GraphicsPalette()) { // ensures palette existence; does nothing if there is a palette on the stack
            var brush = GraphicsPalette.GetSolidBrush(Color.Green); // returns the same brush as in DrawHeader
            ...
        }
    }
}

Поэтому нам нужна GraphicsPalette, чтобы игнорировать вложенную конструкцию и возвращать ту же кисть для данного потока.Предлагаемое решение:

public class GraphicsPalette : IDisposable 
{
    [ThreadStatic]
    private static GraphicsPalette _current = null;
    private readonly Dictionary<Color, SolidBrush> _solidBrushes = new Dictionary<Color, SolidBrush>();

    public GraphicsPalette() 
    {
        if (_current == null)
            _current = this;
    }

    public void Dispose() 
    {
        if (_current == this)
            _current = null;

        foreach (var solidBrush in _solidBrushes.Values)
            solidBrush.Dispose();            
    }

    public static SolidBrush GetSolidBrush(Color color) 
    {
        if (!_current._solidBrushes.ContainsKey(color))
            _current._solidBrushes[color] = new SolidBrush(color);

        return _current._solidBrushes[color];
    }
}
0 голосов
/ 13 марта 2012

Исходя из моего опыта работы с VG.net, я не верю, что кэширование объектов GDI + обычно стоит таких проблем, за исключением крупных вещей, таких как растровые изображения.Конечно, это легко измерить.

...