Выделение неуправляемой памяти в управляемом коде .NET

Привет у меня есть неуправляемая функция, которая занимает кусок памяти, выделенных malloc и deallocates его позже в асин образом. Я хочу завернуть его в управляемую обертку. Является ли следующий код в порядке?

void managed_fx (byte data __gc[], size_t size)
{
    //  Pin the data
    byte __pin *pinned_data = &data [0];

    //  Copy data to the unmanaged buffer.
    void *unmanaged_data = malloc (size);
    memcpy (unmanaged_data, (byte*) pinned_data, size);

    //  Forward the call
    fx (unmanaged_data, size);
}

Ответ на: "Выделение неуправляемой памяти в управляемом коде .NET"

Количество ответов:5
Не знаю, C'/ CLI, поэтому я не знаю, если ваш контактный будет работать. Вам не нужно использовать библиотеку Маршаллинга, чтобы гарантировать, что память будет закреплена при ее копировании?

Вам нужно проверить свой маллок, что он на самом деле выделил указатель.

Подробнее о том, как распределять неуправляемые данные, читайте в материале «-6-» Взгляните на Marshall class. Maybe there would be some method which can replace your managed_fx function. класса. Может быть, там будет какой-то метод, который может заменить вашу функцию managed_fx.

Вы

  1. предполагая, что массив данных, по крайней мере, как большой размер. Это возможная ошибка ждет, чтобы случиться

  2. Не проверяя результат malloc ()

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

С учетом этого здесь фиксированная версия

void managed_fx (byte data __gc[], size_t size)
{
    if (data.Length < size)
        throw gcnew System.IndexOutOfRangeException(
            "the unmanaged buffer is not big enough");
    //  Pin the data
    byte __pin *pinned_data = &data [0];

    //  Copy data to the unmanaged buffer.
    void *unmanaged_data = malloc (size);
    if (unmanaged_data == NULL) 
        throw gcnew OutOfMemoryException(
            "could not allocate memory for the unmanaged buffer");
    memcpy (unmanaged_data, (byte*) pinned_data, size);

    //  Forward the call
    fx (unamanged_data, size);
}

Чтобы ответить на дальнейшие вопросы:

Закрепление необходимо сделать memcpy. Это не предотвращает удаление памяти GC время выполнения (ну технически это делает, но так же просто проведение ссылки на него) он предотвращает его перемещение в памяти. Так как memcpy является неуправляемой функцией - она не может обрабатывать указатели, которыми он манипулирует перемещается в памяти.Поскольку эта операция является небезопасным (если GC ногами в ходы ссылка о) закрепление указатель существует, чтобы сделать это безопасно и просто сделать, поскольку он как занимает указатель и для жизни, что указатель предотвращает время выполнения указал на переменную.

malloc полностью неуправляем (хотя библиотеки времени выполнения свободны в использовании зарезервированных областей управляемой кучи для этого).

Существует нет четкого различия в исходном C q / CLI о том, "код" управляется или не управляется. При компиляции некоторые части будут CIL промежуточный код, другие простой родной код важно ли переменные используется управляются или не управляется. Управляемая ссылка (что-либо с помощью к) может быть обработана или использована только кодом, который сам управляется. Это означает, что время выполнения может изменять значения основных указателей, используемых по мере того, как он считает нужным, если оно изменяет расположение управляемого объекта в памяти. Он делает это таким образом, что является безопасным для управляемых функций (они приостановлены в то время как мир меняется вокруг них).Поскольку многие полезные функции существуют без знания о том, как обрабатывать такие управляемые ссылки вы можете в конечном итоге необходимости принять простой указатель на них.

Хорошо, давайте сделаем это еще проще:

void managed_fx (byte data __gc[])
{
     //  Pin the data
     byte __pin *pinned_data = &data [0];

     //  Copy data to the unmanaged buffer.
     void *unmanaged_data = malloc (data.Length);
     assert (unmanaged_data);
     memcpy (unmanaged_data, (byte*) pinned_data, data.Length);

     //  Forward the call
     fx (unamanged_data, data.Length);
 }

Тем не менее, у меня есть пара вопросов:

  1. Является ли закрепление необходимо на всех в этом случае? Может gc deallocate оно прежде чем memcpy случается?
  2. Выделяет ли malloc неуправляемую память, даже если она используется в управляемом коде?

Мой MC's немного ржавый, но я думаю, что __pin булавки переменной источника до тех пор, пока "pinned_data" выходит из сферы (по крайней мере, это то, что эквивалентная pin_ptr в C q / CLI делает). Как правило, вы должны оон-прикрепить его как можно скорее, т.е. вы не должны вызывать FX в той же области по причинам производительности.

Является ли закрепление необходимо на всех в этом случае?

Да. Требуется получить доступ к управляемой памяти из неуправляемого кода.

Может gc сделки, как это было до memcpy

Нет. Существует сильная ссылка на данные, поэтому gc не будет собирать его. Однако он может собирать какой-либо другой объект и перемещать данные в память на этапе уплотнения. Тогда malloc получит доступ к неправильной области памяти. Закрепление предотвращает это, за счет дополнительной бухгалтерии для GC (именно поэтому вы должны оон-контактные объекты как можно скорее).

Выделяет ли malloc неуправляемую память, даже если она используется в управляемом коде?

Да.