Утечка памяти, если Bitmap получает необработанные данные от Marshal.AllocHGlobal? - PullRequest
1 голос
/ 26 декабря 2010

Мне не совсем понятна механика нативного взаимодействия.

Предположим, я делаю следующее:

IntPtr nativeArray = Marshal.AllocHGlobal(stride * height);
someNativeCallToFillRawImageData(nativeArray, width, stride, height);
return new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, nativeArray);

Мой выделенный массив является источником растрового изображения (оно работает),но я не уверен, будет ли когда-нибудь очищена память для него?

В качестве альтернативы я могу сделать следующее (изменив сигнатуру DLLImport ... родной метод изначально определен как (unsigned char * buff)):

byte[] managedArray = new byte[stride * height];
someNativeCallToFillRawImageData(managedArray, width, stride, height);
fixed (byte* ptr = managedArray)
{
   return new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, new IntPtr(ptr));
}

, который также работает, но я не совсем точно понимаю разницу.У меня также сложилось впечатление, что первый вариант быстрее, поскольку ему не нужно пересекать управляемые / неуправляемые границы.

Располагает ли управляемый растровый объект данными в Scan0, даже если они были кем-то выделеныеще?bitmap.Dispose () -> что происходит с выделенной памятью в managedArray или nativeArray?

Заранее большое спасибо!

Ответы [ 3 ]

2 голосов
/ 26 декабря 2010

Если используется Marshal.AllocHGlobal и растровое изображение копирует данные из указателя, вы должны освободить их с помощью Marshal.FreeHGlobal. Я советую вам прочитать MSDN на конструкторе BitMap относительно того, копирует ли он данные или просто использует указатель; если он просто использует указатель, вы должны подождать, чтобы освободить его.

1 голос
/ 26 декабря 2010

Вы должны создать метод Dispose в классе, который использует неуправляемый ресурс (в вашем случае nativeArray) и освободить его, используя Marshal.FreeHGlobal(nativeArray ).Примерно так:

if(nativeArray != IntPtr.Zero)
    Marshal.FreeHGlobal(nativeArray);

Вы отвечаете за вызов созданного метода Dispose.

1 голос
/ 26 декабря 2010

Не думаю, что вам нужно выделять память самостоятельно. Создайте пустое растровое изображение с нужным размером, затем вызовите LockBits для доступа к необработанным данным пикселей:

Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
Rectangle rect = new Rectangle(width, height);
BitmapData data = null;
try
{
    data = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
    someNativeCallToFillRawImageData(data.Scan0, data.Width, data.Stride, data.Height);
}
finally
{
    if (data != null)
        bmp.UnlockBits(data);
}

Таким образом, память обрабатывается объектом Bitmap, поэтому вам не нужно об этом беспокоиться.

...