Понимание различий между использованием fixed {}, Marshal.AllocHGlobal () и GCHandle.Alloc () - PullRequest
14 голосов
/ 02 января 2011

Позвольте мне начать с того, что я посмотрел и нашел описания использования fixed {}, Marshal.AllocHGlobal () и GCHandle.Alloc () на этом форуме и во многих ссылках в Интернете.Тем не менее, мне еще предстоит найти краткое объяснение того, когда использовать класс Marshal против класса GCHandle (с использованием и без использования fixed {}).

Я использую стороннюю библиотеку .NET, котораяимеет метод с именем Readline () в классе «Buffer».В руководстве показан следующий прототип функции:

bool ReadLine (int x1, int y1, int x2, int y2, System.IntPtr bufData, out int numRead);

с описанием bufData, которое гласит: ... Область памяти должна иметь число байтов, большее или равное длине строки, умноженной на значение, возвращаемое свойством BytesPerPixel.

Позже в руководстве пользователя они do дают пример доступа к буферу (который я немного подправил для моего конкретного примера):

// Create an array large enough to hold one line from buffer
int size = 640; 
byte[] dataLine = new byte[size * 2];   // 2 bytes per pixel

// Pin the array to avoid Garbage collector moving it  
GCHandle dataLineHandle = GCHandle.Alloc(dataLine, GCHandleType.Pinned); 
IntPtr dataLineAddress = dataLineHandle.AddrOfPinnedObject(); 

, и я мог бы следоватьприведенный выше пример кода с:

// Read one line of buffer data 
success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead); 

// Unpin the array 
dataLineHandle.Free() 

Это может быть концом истории (и я еще не протестировал приведенный выше код), но я в конечном итоге погуглил класс GCHandle, что привело меня в путьвзаимодействия .NET, pInvoke и т. д.

Итак, мои вопросы ... 1) Почему я не могу использовать:

IntPtr dataLineAddress = Marshal.AllocHGlobal( size * 2 );

и передать это в ReadLine ()?

2) Могу ли я также использовать следующий фрагмент кода (извлеченный и настроенный из examples on the web):

int size = 640;
byte[] dataLine= new byte[size * 2];  // 2 bytes per pixel

// prevent garbage collector from moving buffer around in memory
fixed (byte* fixedDataLine = dataLine)
{
  // get IntPtr representing address of first buffer element
  IntPtr dataLineAddress= Marshal.UnsafeAddrOfPinnedArrayElement(fixedDataLine , 0);
  success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead);
}

Мне было бы интересно, чтобы кто-нибудь мог пролить свет на вышеуказанные методы и указать на мои ошибки в реализации, а также указать, когда вышеуказанные методы являются подходящими.Наконец, даже если все вышеперечисленные методы действительны, есть ли общий толчок в последние несколько лет к одному или другому подходу?

Заранее спасибо !!Раздутый

1 Ответ

3 голосов
/ 02 января 2011

Ну, альтернатива, вероятно, тоже будет работать.Но образец Marshal.AllocHGlobal не завершен, теперь вы получили данные в неуправляемой памяти.Вам все еще нужно проделать работу, чтобы поместить его в управляемый объект (массив), чтобы вы могли легко получить к нему доступ, вы должны вызвать Marshal.Copy ().Неэффективно, поскольку это копирует данные дважды.И не забывайте вызывать Marshal.FreeHGlobal ().

Фиксированный образец делает то же самое, что и образец поставщика, он неявно закрепляет память.Неудобство здесь в том, что API принимает IntPtr, а не байт *.И вы должны изменить параметры компиляции, чтобы разрешить ключевое слово unsafe .В остальном он не более эффективен.

Вы не впереди, если сделаете это по-другому.

...