2012-02-14 10 views
9

私のwinformsアプリケーションの中には、GDI +オブジェクト(ブラシ、ペン、フォントなど)をたくさん作成し、それらを何度も何度も使用する必要があります。私は私が必要なものを達成するためにゲットー・キャッシング・シングルトンを作成しますが、コードのにおいが圧倒的です...私はこれらのGDI +のオブジェクトを再利用するためにすべての上にそれらをインスタンス化とは対照的に、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. は良い方法は、あります再びOnPaint()などが呼び出されるたびに?
  2. プログラムが終了したら、GDI +オブジェクトは、アンマネージメモリリークが発生します、または各Brushオブジェクトのファイナライザは、ターンリリース内のどの意志任意のアンマネージリソースと呼ばれますか?

これが繰り返しである場合はお詫び申し上げますが、似たような質問はありません。

+0

シングルトンを調整することで、パフォーマンスの向上を簡単にテストできます。シングルトンとAの間で切り替えるためのフラグを追加します... "マルチトン"(私はその言葉を作った)。マルチトンは常にリソースを削除して再作成します。その後、ここに報告してください。 –

+0

[ユーザーコントロールでBrushを処理するにはどのような方法が良いですか](http://stackoverflow.com/questions/8253398/what-is-better-approach-to-dispose-brush-in-user-control) –

+0

あんまり。私が見つけようとしているのは、GDI +オブジェクト(ブラシ)の束にぶら下がって明示的にDispose()を呼び出さないと、それらがすべて正しくファイナライズされ、自動的に破棄されるという保証があります。私のアプリケーションドメインは終了しますか?そうでない場合、私はアンマネージメモリリークを探しています。 –

答えて

4

メモリリークは発生しませんが、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

良い答えです。私は実際にシングルトンではなく、winformsコントロール内でGDIオブジェクトをキャッシュすることを検討しました。そうすれば、コントロールのdisposeメソッドにフックして、コントロールが不要になったり、特定のフォームが閉じられたりするときにオブジェクトを取り除くことができます。 –

0

VG.netとの私の経験に基づいて、私はキャッシュGDI +オブジェクトを信じないはビットマップのような大規模なものを除き、トラブルの通常の価値があります。もちろん、測定するのは簡単です。

+0

私はERM Diagram/Crainiate Diagram/Open Diagramの長年の経験に基づいて同意します。 1つ以上のビットマップを再利用し、それらを投げ捨てるのは間違いありません。 –

関連する問題