.Net и Bitmap не удаляются автоматически GC, когда не осталось памяти - PullRequest
8 голосов
/ 30 апреля 2011

Мне интересно, как работает распределение и распределение памяти, выделенной для растровых изображений, в .NET.

Когда я выполняю много растровых операций в циклах в функции и вызываю ее последовательно, она будет работатьдо тех пор, пока в какой-то момент растровое изображение не сможет выделить память с исключением «Неверный параметр» для указанного размера.

Если я вызываю сборщик мусора время от времени, пока он работает.

С помощью следующего кода вы можете воспроизвести ошибку:

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
        }       
     }
}

Ответы [ 3 ]

17 голосов
/ 01 мая 2011

Класс Bitmap неизбежно является тем, где у вас есть , чтобы прекратить игнорировать существование IDisposable. Это небольшой класс-оболочка вокруг объекта GDI +. GDI + - это неуправляемый код. Растровое изображение занимает неуправляемую память. Многое, когда растровое изображение большое.

.NET сборщик мусора гарантирует, что неуправляемые системные ресурсы высвобождаются с потоком финализатора. Проблема в том, что он срабатывает только тогда, когда вы создаете достаточное количество управляемых объектов для запуска сборки мусора. Это не будет хорошо работать для класса Bitmap, вы можете создать их много тысяч до того, как поколение # 0 заполненной кучи мусора заполнится. Вам не хватит неуправляемой памяти, прежде чем вы сможете туда добраться.

Требуется управление временем жизни используемых вами растровых изображений. Вызовите метод Dispose (), когда он больше не используется. Это не всегда золотое решение, вам, возможно, придется пересмотреть свой подход, если у вас просто слишком много живых растровых изображений. 64-разрядная операционная система является следующим решением.

14 голосов
/ 30 апреля 2011

.NET Bitmap класс "инкапсулирует растровое изображение GDI +", что означает, что вы должны вызвать Dispose для Bitmap, когда закончите с ним,

"Всегда звоните утилизировать перед вами отпустите последнюю ссылку на Образ. В противном случае ресурсы это использование не будет освобождено до сборщик мусора называет изображение Метод Finalize объекта. "

1 голос
/ 30 апреля 2011

Почему бы вам не использовать ключевое слово using.Просто инкапсулируйте в него свой растровый объект, и Compiler обеспечит вызов метода Dispose.

Это просто синтаксический ярлык для

try
{
 ...   
}
finally
{
    ...Dispose();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...