C # освобождает память, на которую ссылается IntPtr - PullRequest
10 голосов
/ 20 февраля 2010

Я использую некоторый неуправляемый код, который возвращает указатели (IntPtr) на большие объекты изображения. Я использую ссылки, но после того, как я закончу с изображениями, мне нужно освободить память, на которую ссылаются указатели. В настоящее время единственное, что освобождает память, - это отключение всего моего приложения. Мне нужно иметь возможность освободить эту память из моего приложения.

Вот вызов, который выделяет память. hbitmap - указатель, который возвращается и должен быть освобожден.

[DllImport("twain_32.dll", EntryPoint = "#1")]
public static extern TwainResult DsImageTransfer(
    [In, Out] Identity origin, [In] Identity dest, DataGroup dg, 
    DataArgumentType dat, Message msg, ref IntPtr hbitmap);

Ответы [ 6 ]

8 голосов
/ 20 февраля 2010

Вам необходимо использовать механизм выделения памяти , специфичный , который использовался для выделения памяти в первую очередь.

Итак, если вы использовали COM и IMalloc интерфейс для выделения памяти, то вам нужно передать IntPtr обратно Free метод в этой реализации для освобождения выделенной памяти.

Если вы действительно используете COM-распределитель, который возвращается при вызове CoGetMalloc, то вы можете вызвать static FreeCoTaskMem метод на Marshal класс .

Класс Marshal также имеет метод для освобождения памяти, который выделяется посредством вызова LocalAlloc, называемого FreeHGlobal.

Однако, и это распространенный случай, если память была выделена оператором new в C ++ или вызовом malloc в C, тогда вы необходимо предоставить функцию в неуправляемом коде через взаимодействие, которое освободит память соответствующим образом.

В случае C ++ вы бы представили функцию, которая принимает указатель и просто вызывает delete для этого указателя. В случае malloc вы должны создать функцию, которая принимает указатель и вызывает free для этого указателя.

В конкретном отношении к вашему вопросу может показаться, что DsImageTransfer является API-интерфейсом, специфичным для поставщика (у которого не так много возможностей для обнаружения в Интернете , я боюсь), поэтому требуется дополнительная информация об этой конкретной функции API и о том, как она распределяет память. Знание типа дескриптора (в данном случае HBITMAP) не дает никаких указаний относительно его распределения. Он может быть наделен всеми механизмами, упомянутыми выше.

Если предположить, что он создает HBITMAP с использованием функций API объекта GDI (в частности, CreateBitmap function ), тогда вы можете использовать функцию DeleteObject для освобождения дескриптора (согласно странице документации для функций API GDI Object).

4 голосов
/ 20 февраля 2010

Это будет зависеть от того, как эта память была выделена.Класс Marshal имеет методы для освобождения памяти, выделенной с помощью общих шаблонов распределения взаимодействия, таких как FreeCoTaskMem .Если неуправляемый код использует способ распределения, не совместимый с Interop, вы не сможете с ним взаимодействовать.

Обновлено

Если я рискну предположить, функция # 1Вы вызываете в twain_32.dll функцию DS_ENTRY в TWAIN-провайдере.Спецификации Twain вызывают протокол управления ресурсами памяти:

Управление памятью в TWAIN 2.0 и выше
Для TWAIN требуются приложения и источники для управления каждымпамять другого.Основная проблема заключается в гарантировании соглашения об использовании API.TWAIN 2.0 представляет четыре новые функции, которые можно получить из менеджера исходного кода через DAT_ENTRYPOINT.

TW_HANDLE PASCAL DSM_MemAllocate (TW_UINT32)
PASCAL DSM_MemFree (TW_HANDLE)
TW_MEMREF PASCAL DSM_MemLock(TW_HANDLE)
void PASCAL DSM_MemUnlock(TW_HANDLE)

Эти функции соответствуют функциям глобальной памяти WIN32, упомянутым в предыдущих версиях спецификации TWAIN: GlobalAlloc, GlobalFree, GlobalLock, GlobalUnlock
В MacOS / X эти функции вызывают NewPtrClear и DisposePtr.Функции блокировки и разблокировки запрещены, но они все равно должны быть вызваны.Приложения и источники, совместимые с TWAIN 2.0, должны использовать эти вызовы на всех платформах (Windows, MacOS / X и Linux).Source Manager берет на себя ответственность за то, чтобы все компоненты использовали один и тот же API управления памятью.

Таким образом, чтобы освободить ресурсы, вы должны вызывать DSM_MemFree, который предположительно на платформах Win32 будет реализован через GlobalFree или Marshal.FreeHGlobal .

Так как это в основном спекуляция с моей стороны, вам лучше проверить спецификации конкретной используемой вами реализации TWAIN.

2 голосов
/ 20 февраля 2010

Пожалуйста, покажите свой неуправляемый код. Существуют разные способы выделения памяти на неуправляемой земле, и вы должны использовать правильные соответствующие средства освобождения. Вы, вероятно, в конечном итоге внедрите Finalizer и IDisposable и внедрите шаблон Dispose, как описано здесь: http://www.codeproject.com/KB/cs/idisposable.aspx

2 голосов
/ 20 февраля 2010

Это зависит. Есть ли у вас документация (или исходный код) для нативных функций, которые вы вызываете?

Нативный код не имеет единственной функции освобождения. Это одно из больших преимуществ CLR.

Если бы я был игроком, делающим ставки, я бы пошел на GlobalFree . Но пробовать различные API-интерфейсы будет не очень весело, пока ваш код не перестанет работать.

0 голосов
/ 20 февраля 2010

Как все остальные указывают, это зависит от того, как оно было выделено. Однако, если это действительно карта битов Win32, вы освобождаете ее с помощью функции Win32 «DeleteObject».

0 голосов
/ 20 февраля 2010

Возможно, вы могли бы попытаться создать объект Bitmap из hBitmap и затем удалить его.

Bitmap bitmap = Bitmap.FromHBitmap(hBitmap);
bitmap.Dispose();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...