当 Marshal.FreeHGlobal() 失败时,如何确保此共享库中的内存安全?

问题描述 投票:0回答:1

我有一个在 Unity 项目中使用的 C# 脚本。 C# 脚本导入一个 Dll,这是我用 C++ 编写的函数。在我的 C# 脚本中,我想调用 C++ 函数,对函数返回的数据执行某些操作,然后释放所有内存。我很困惑,因为我认为 Marshal.FreeHGlobal() 是调用的正确函数,但它在实践中会导致错误。我认为我不应该释放 C++ 函数中的内存,因为当该函数在 C# 中返回时我仍然需要使用数据。这是我正在使用的两个函数以及我认为属于 Marshal.FreeHGlobal() 的注释

C#

  void OnMessage(Message message) {
    byte[] byteArray =
        message.payload.ToByteArray();
    int currentFrameWidth = (int)message.payload.Width;
    int currentFrameHeight = (int)message.payload.Height;
    int decodedFrameLength;
    IntPtr output = MyCppFunction(
        byteArray, byteArray.Length, out decodedFrameLength);

    byte[] resultByteArray = new byte[decodedFrameLength];
    Marshal.Copy(output, resultByteArray, 0, decodedFrameLength);
    
    // Attempting to call this causes an error "free(): invalid pointer"
    // Marshal.FreeHGlobal(output);
    
    Debug.Log("decoded frame length was: " + decodedFrameLength + " and resultByteArray length was: " + resultByteArray.Length);
    if (resultByteArray.Length > 0) {
      //Do stuff with resultByteArray
    }
  }

C++

  unsigned char* MyCppFunction(const unsigned char* messagePtr,
                                  int messageSize, int* decodedFrameLength) {
  std::vector<uint8_t> decoded_img(33554432);
  int decoded_len = 0;

  decoder_->DecodeFrame(
      reinterpret_cast<const unsigned char*>(messagePtr), messageSize,
      reinterpret_cast<unsigned char*>(decoded_img.data()), &decoded_len,
      33554432);

  *decodedFrameLength = decoded_len;
  unsigned char* outputData = new unsigned char[decoded_len];
  std::memcpy(outputData, reinterpret_cast<unsigned char*>(decoded_img.data()),
              decoded_len);

  return outputData;
}
c# c++ memory-management
1个回答
0
投票

你不能依赖 C# 来理解 C++ 的内存分配在做什么。您需要从 C# 端传入一个缓冲区。

C++ 中类似以下内容

void MyCppFunction(
  const unsigned char* messagePtr,
  int messageSize,
  unsigned char* outputData,
  int* decodedFrameLength)

等效的

DllImport
看起来像这样:

[DllImport("libraryname.dll")]
void MyCppFunction(
  byte[] messagePtr,
  int messageSize,
  [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
  byte[] outputData,
  ref int decodedFrameLength);

您根本不需要整理任何内容,因为这一切都是自动完成的。

void OnMessage(Message message)
{
    byte[] byteArray =
        message.payload.ToByteArray();
    int currentFrameWidth = (int)message.payload.Width;
    int currentFrameHeight = (int)message.payload.Height;
    int decodedFrameLength = 33554432;
    byte[] resultByteArray = new byte[decodedFrameLength];
    IntPtr output = MyCppFunction(
        byteArray, byteArray.Length, buffer, ref decodedFrameLength);
    //
}
© www.soinside.com 2019 - 2024. All rights reserved.