Правила управления памятью

Время существования указателей на интерфейсы всегда управляется методами AddRef и Release в каждом интерфейсе COM. Дополнительные сведения см. в разделе "Правила для управления счетчиками ссылок".

Для всех остальных параметров важно придерживаться определенных правил управления памятью. Следующие правила применяются ко всем параметрам методов интерфейса, включая возвращаемое значение, которые не передаются по значению:

  • Параметры должны быть выделены и освобождены вызывающим объектом.
  • Параметры вне должны быть выделены одним из вызываемых; они освобождаются вызывающим оператором с помощью стандартного средства выделения памяти задачи COM. Дополнительные сведения см . в параметре OLE Memory Allocator .
  • В/вне параметры изначально выделяются вызывающим объектом, а затем освобождаются и перераспределяются вызываемым, при необходимости. Как и для параметров out, вызывающий отвечает за освобождение окончательного возвращаемого значения. Необходимо использовать стандартный инструмент выделения памяти COM.

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

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

  • В случае ошибки параметры всегда должны быть надежно заданы в значение, которое будет очищаться без каких-либо действий вызывающей стороны.
  • Все параметры указателя выхода должны быть явно заданы как NULL. Обычно они передаются в параметр указателя на указатель, но также могут передаваться как члены структуры, которую вызывающий объект выделяет и вызываемые заливки кода. Самый простой способ убедиться, что это (в части) для задания этих значений значение NULL для записи функции. Это правило важно, так как оно способствует более надежному взаимодействию приложений.
  • При условии ошибки все параметры вне сети должны быть оставлены в одиночку вызываемым кодом (таким образом, оставшимся в значении, в котором они были инициализированы вызывающим оператором) или явно заданы, как в случае возврата ошибки параметров out.

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

Warning

Распространенные ошибки в взаимодействии .NET/ управляемого кода: при использовании COM-интерфейсов из .NET (C# или VB.NET), вызываемая оболочка среды выполнения (RCW) автоматически обрабатывает большинство управления памятью. Однако если вы P/Invoke a COM-style function, который возвращает выделенную CoTaskMemAllocстроку (вне LPWSTR), ее необходимо освободить с Marshal.FreeCoTaskMem помощью— сборщик мусора не освобождает память задачи COM:

// C# example — COM function returns a CoTaskMemAlloc'd string
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
static extern int SHGetKnownFolderPath(
    ref Guid rfid, uint dwFlags, IntPtr hToken, out IntPtr ppszPath);

// Caller must free the returned string
IntPtr pathPtr = IntPtr.Zero;
try
{
    Guid folderId = new("374DE290-123F-4565-9164-39C4925E467B"); // Downloads
    int hr = SHGetKnownFolderPath(ref folderId, 0, IntPtr.Zero, out pathPtr);
    Marshal.ThrowExceptionForHR(hr);
    string path = Marshal.PtrToStringUni(pathPtr)!;
}
finally
{
    if (pathPtr != IntPtr.Zero)
        Marshal.FreeCoTaskMem(pathPtr); // Required — prevents memory leak
}

Правило отпечатка: Если собственный com-функции документирует, что вызывающий объект должен освободить параметр out-with CoTaskMemFree, управляемый эквивалент равен Marshal.FreeCoTaskMem. Никогда не используется Marshal.FreeHGlobal для памяти задач COM, так как это разные распределители.

COM использует удаленные вызовы процедур (RPC) для обмена данными между клиентами и серверами. Дополнительные сведения об управлении памятью в заглушках сервера RPC см. в разделе "Управление памятью с заглушки сервера ".