熱點推薦:
您现在的位置: 電腦知識網 >> 操作系統 >> Windows優化 >> 正文

小心GDI+資源洩漏 -- 猜想 測試 應對全過程

2013-11-12 16:44:36  來源: Windows優化 

  讀到一篇文章利用GDI+的雙緩沖技術來提高繪圖效率懷疑其中的示例代碼會引起GDI+洩漏試驗之後發現果然如此將代碼簡化為
  
  public void TestGdiLeak()
  {
    Bitmap bmp = new Bitmap( );
    Graphics g = GraphicsFromImage(bmp);
    Brush brush = new LinearGradientBrush
      (new PointF(f f)
      new PointF(f f)
      ColorBlue ColorRed);
    for (int j = ; j < 60; ++j)
      for(int i = 0; i < 60; ++i)
        g.FillEllipse(brush, i * 10, j * 10, 10, 10);
    this.CreateGraphics().DrawImage(bmp, 0, 0);
  }
  要測試上述代碼,進行如下操作:
  新建一個Windows Application(C# Form)應用;
  將TextGdiLeak添加為Form1的成員;
  在Form1上放置一個Timer timer1,將其Interval設為10;
  在Form1構造函數中調用timer1.Start();
  在timer1的Tick事件處理函數中調用TestGdiLeak方法);
  在適當的地方調用timer1.Stop()。tW.WInGWiT.com
  編譯運行該應用,打開“Windows任務管理器”檢查其進程,發現內存使用率不停地上升。顯然,是GDI+使用不當造成的。初步猜測為在每次timer1的Tick事件調用該方法時,Bitmap對象沒有被及時地垃圾收集掉。嘗試將代碼修改為:
  public void TestGdiLeak()
  {
    using (Bitmap bmp = new Bitmap(600, 600))
    {
      Graphics g = Graphics.FromImage(bmp);
      Brush brush = new LinearGradientBrush
        (new PointF(0.0f, 0.0f),
        new PointF(700.0f, 300.0f),
        Color.Blue, Color.Red);
      for (int j = 0; j < 60; ++j)
        for(int i = 0; i < 60; ++i)
          g.FillEllipse(brush, i * 10, j * 10, 10, 10);
      this.CreateGraphics().DrawImage(bmp, 0, 0);
    }
  }
  再次編譯運行,發現情況並沒有好轉。猜測Graphics對象g可能也沒有被及時收集,同時由於g與bmp有關聯,也影響了bmp的收集。再將代碼修改為:
  
  public void TestGdiLeak()
  {
    using (Bitmap bmp = new Bitmap(600, 600))
    {
      using (Graphics g = Graphics.FromImage(bmp))
      {
        Brush brush = new LinearGradientBrush
          (new PointF(0.0f, 0.0f),
          new PointF(700.0f, 300.0f),
          Color.Blue, Color.Red);
        for (int j = 0; j < 60; ++j)
          for(int i = 0; i < 60; ++i)
            g.FillEllipse(brush, i * 10, j * 10, 10, 10);
        this.CreateGraphics().DrawImage(bmp, 0, 0);
      }
    }
  }
  
  再次編譯運行,內存使用率已穩定在一個常數范圍內。
  
  由此可見GDI+使用中(其他.Net對象也一樣)要十分小心類似的情況,.Net Framework可以非常好地工作,前提是程序員寫的代碼足夠符合其機制。對於資源對象,象上述代碼中一樣使用using能保證它們被及時的垃圾收集(當然使用using的對象必須IDispose接口)。針對上例還有另外一種簡單的解決方法,就是將Bitmap、Graphics等對象抽出TestGdiLeak方法作為Form1的類成員,並只對它們進行一次new操作

From:http://tw.wingwit.com/Article/os/youhua/201311/10788.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.