Если вы экспортируете память, выделенную с помощью malloc, ее необходимо освободить с помощью free из той же среды выполнения, что и для malloc. Вы можете бесплатно экспортировать из своей DLL, но это может быть не самым элегантным решением.
Marshal.FreeCoTaskMem для использования в памяти, выделенной выделенным COM. Таким образом, вы должны использовать это в управляемом коде, чтобы освободить память, выделенную неуправляемым вызовом CoTaskMemAlloc. Это хорошее решение вашей проблемы.
В другом ответе предлагается освободить память с помощью Marshal.FreeHGlobal, которая будет работать при условии, что она была выделена с помощью LocalAlloc. Это довольно утомительный API для использования, и я бы всегда предпочел COM-распределитель для его удобства.
Если вы экспортируете строки, рассмотрите возможность использования BSTR, который выделяется распределителем COM и может быть автоматически распакован маршаллером .net.