메모리 관리 규칙

인터페이스에 대한 포인터의 수명은 항상 모든 COM 인터페이스에서 AddRefRelease 메서드를 통해 관리됩니다. 자세한 내용은 참조 개수 관리하기 위한규칙을 참조하세요.

다른 모든 매개 변수의 경우 메모리 관리에 대한 특정 규칙을 준수하는 것이 중요합니다. 다음 규칙은 값으로 전달되지 않는 반환 값을 포함하여 인터페이스 메서드의 모든 매개 변수에 적용됩니다.

  • 매개 변수 내는 호출자가 할당하고 해제해야 합니다.
  • out 매개 변수는 호출된 매개 변수에 의해 할당되어야 합니다. 표준 COM 작업 메모리 할당자를 사용하여 호출자가 해제합니다. 자세한 내용은 OLE 메모리 할당자 참조하세요.
  • In/out 매개 변수는 처음에 호출자에 의해 할당된 다음 필요한 경우 호출된 매개 변수에 의해 해제되고 다시 할당됩니다. out 매개 변수의 경우와 마찬가지로 호출자는 최종 반환 값의 해제를 담당합니다. 표준 COM 메모리 할당자를 사용해야 합니다.

후자의 두 경우에서 한 코드 조각이 메모리를 할당하고 다른 코드 조각이 해제되는 경우 COM 할당자를 사용하면 두 코드 조각이 동일한 할당 메서드를 사용하게 됩니다.

특별한 주의가 필요한 또 다른 영역은 오류 조건에서 아웃 및 인아웃 매개 변수의 처리입니다. 함수가 오류 코드를 반환하는 경우 호출자는 일반적으로 out 또는 in-out 매개 변수를 정리할 방법이 없습니다. 이로 인해 다음과 같은 추가 규칙이 발생합니다.

  • 오류 조건의 경우 매개 변수는 항상 호출자의 작업 없이 정리되는 값으로 안정적으로 설정되어야 합니다.
  • 모든 out 포인터 매개 변수는 NULL 명시적으로 설정해야 합니다. 이러한 매개 변수는 일반적으로 포인터 대 포인터 매개 변수로 전달되지만 호출자가 할당하고 호출된 코드가 채우는 구조체의 멤버로 전달될 수도 있습니다. 이를 보장하는 가장 간단한 방법은 함수 항목에서 이러한 값을 NULL 설정하는 것입니다. 이 규칙은 보다 강력한 애플리케이션 상호 운용성을 촉진하므로 중요합니다.
  • 오류 조건에서 모든 인아웃 매개 변수는 호출된 코드(따라서 호출자가 초기화한 값에 남아 있어야 함)에 의해 단독으로 남겨지거나 out 매개 변수 오류 반환 사례에서와 같이 명시적으로 설정해야 합니다.

COM 애플리케이션에 대한 이러한 메모리 관리 규칙은 공용 인터페이스 및 API에만 적용됩니다. 이러한 메커니즘을 사용하여 COM 애플리케이션 내부로 엄격하게 메모리 할당을 수행해야 하는 요구 사항은 전혀 없습니다.

Warning

.NET/관리 코드 interop의 일반적인 문제: .NET(C# 또는 VB.NET)에서 COM 인터페이스를 사용하는 경우 RCW(런타임 호출 가능 래퍼)는 대부분의 메모리 관리를 자동으로 처리합니다. 그러나 할당된 문자열(a outLPWSTR)을 반환CoTaskMemAlloc하는 COM 스타일 함수를 P/Invoke하는 경우 해제해야 합니다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 매개 변수를 CoTaskMemFree해제해야 한다고 문서화하는 경우 관리되는 해당 함수는 Marshal.FreeCoTaskMem다음과 같습니다. COM 작업 메모리는 서로 다른 할당자이므로 사용하지 Marshal.FreeHGlobal 마세요.

COM은 내부적으로 RPC(원격 프로시저 호출)를 사용하여 클라이언트와 서버 간에 통신합니다. RPC 서버 스텁에서 메모리를 관리하는 방법에 대한 자세한 내용은 Server-stub 메모리 관리 항목을 참조하세요.