2011-04-30 134 views
7

我想知道分配給位圖的內存分配和處理如何在.NET中工作。。當沒有剩餘內存時,GC不會自動處理.Net和位圖

當我在一個函數的循環中進行了大量的位圖創建並連續調用它時,它將一直運行,直到某些時候位圖將不能分配給出指定大小的「無效參數」異常的內存。

如果我從while調用垃圾回收器的時候它工作。

用下面的代碼,你能repoduce錯誤:

class BitmapObject { 
    public bool Visible { 
     get { return enb; } 
     set { enb = value; } 
    } 
    private bool enb; 
    private Bitmap bmp; 
public BitmapObject(int i, bool en) 
{ 
    enb = en; 
    bmp = new Bitmap(i, i); 


    } 
} 

class Pool<T> where T : BitmapObject 
{ 
    List<T> preallocatedBitmaps = new List<T>(); 
public void Fill() { 
    Random r = new Random(); 
    for (int i = 0; i < 500; i++) { 
     BitmapObject item = new BitmapObject(500, r.NextDouble() > 0.5); 
     preallocatedBitmaps.Add(item as T); 
    } 
} 

public IEnumerable<T> Objects 
{ 
    get 
    { 
     foreach (T component in this.preallocatedBitmaps) 
     { 
      if (component.Visible) 
      { 
       yield return (T)component; 
      } 
     } 


    } 
    } 
} 

static class Program 
{ 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
{ 
    for (int i = 0; i < 10; i++) 
    { 
     Test(); 

      // without this it breaks 
      //GC.Collect(); 
      //GC.WaitForPendingFinalizers(); 
     } 

     Console.ReadKey(); 
    } 

    private static void Test() { 
     Pool<BitmapObject> pool = new Pool<BitmapObject>(); 
     pool.Fill(); 

     for (int i = 0; i < 100; i++) 
     { 
      var visBitmaps = pool.Objects; 
      // do something 
     }  
    } 
} 
+2

GC *從不清理本地資源,只清理Bitmap對象本身。你有責任調用Dispose()。 – 2011-04-30 00:28:20

+0

@Ed,儘管技術上是這樣,當GC清理位圖時,位圖的終結器將處理該資源。但是你是對的,你不應該依賴它。 – Talljoe 2011-04-30 00:33:09

+0

@Talljoe:是的,你是對的,會的。 – 2011-04-30 00:42:36

回答

14

的.NET Bitmap類「封裝了GDI +位圖」,這意味着你應該在BitmapDispose當你用它完成,

"Always call Dispose before you release your last reference to the Image. Otherwise, the resources it is using will not be freed until the garbage collector calls the Image object's Finalize method."

+0

這意味着如果在泛型類中使用了一些位圖,那麼泛型類應該實現IDIsposable,並且T必須是一次性的以便被類調用? – 2011-04-30 00:33:27

1

爲什麼不使用using關鍵字。只需將您的Bitmap對象封裝在其中,編譯器將確保調用Dispose方法。

它只是爲

try 
{ 
... 
} 
finally 
{ 
    ...Dispose(); 
} 
+1

,因爲位圖可以是在通用外部列表中使用的類的私有字段......但我認爲IDisposable是要去的地方... – 2011-04-30 00:36:01

17

Bitmap類句法快捷方式必然是一個在那裏你停止忽略了IDisposable的存在。這是一個圍繞GDI +對象的小包裝類。 GDI +是非託管代碼。位圖佔用非託管內存。當位圖很大時,它很多。

.NET垃圾收集器確保使用終結器線程釋放非託管系統資源。問題是,當你創建足夠數量的對象來觸發垃圾收集時,它纔會採取行動。這對Bitmap類來說不太好,你可以在垃圾收集堆的第0代填滿之前創建數千個。你可以在你到達那裏之前用完非託管內存。

管理您使用的位圖的生命週期是必需的。當你不再使用它時調用Dispose()方法。這並不總是最好的解決方案,如果您的活體位圖太多,您可能不得不重新考慮您的方法。下一個解決方案是64位操作系統。