.Net y Bitmap no son eliminados automáticamente por GC cuando no queda memoria

Me pregunto cómo funciona la asignación y eliminación de memoria asignada para bitmaps en .NET.

Cuando hago muchas creaciones de bitmap en bucles en una función y la llamo en sucesión, funcionará hasta que en algún momento el bitmap no podrá asignar memoria con la excepción de “Parámetro no válido” para el tamaño especificado.

Si llamo al recolector de basura de mientras tanto funciona.

Con el siguiente código, puede volver a generar el error:

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 where T : BitmapObject { List preallocatedBitmaps = new List(); public void Fill() { Random r = new Random(); for (int i = 0; i  0.5); preallocatedBitmaps.Add(item as T); } } public IEnumerable Objects { get { foreach (T component in this.preallocatedBitmaps) { if (component.Visible) { yield return (T)component; } } } } } static class Program { ///  /// The main entry point for the application. ///  [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 pool = new Pool(); pool.Fill(); for (int i = 0; i < 100; i++) { var visBitmaps = pool.Objects; // do something } } } 

La clase .NET Bitmap “encapsula un bitmap GDI +”, lo que significa que debe llamar a Dispose en un Bitmap cuando haya terminado con él,

“Siempre llame a Dispose antes de lanzar su última referencia a la imagen. De lo contrario, los recursos que está utilizando no se liberarán hasta que el recolector de basura llame al método Finalize del objeto Image.”

La clase Bitmap es inevitablemente aquella en la que debes dejar de ignorar que existe IDisposable. Es una clase de contenedor pequeña alrededor de un objeto GDI +. GDI + es un código no administrado. El bitmap ocupa la memoria no administrada. Mucho cuando el bitmap es grande.

El recolector de elementos no utilizados de .NET garantiza que los recursos del sistema no administrados se liberen con la secuencia del finalizador. El problema es que solo entra en acción cuando crea cantidades suficientes de objetos administrados para desencadenar una recolección de basura. Eso no funcionará bien para la clase de bitmap, puede crear muchos miles de ellos antes de que se llene la generación n.º 0 del montón recogido de basura. Te quedarás sin memoria no administrada antes de que puedas llegar allí.

Se requiere administrar la vida útil de los mapas de bits que usa. Llame al método Dispose () cuando ya no tenga un uso para él. Esa no es siempre la solución de oro, es posible que deba volver a pensar su enfoque si simplemente tiene demasiados mapas de bits en vivo. Un sistema operativo de 64 bits es la siguiente solución.

¿Por qué no using palabra clave? Simplemente encapsula el objeto Bitmap en él y Compiler se asegurará de que se invoque el método Dispose.

Es simplemente un atajo sintáctico para

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