c# - Marshal.AllocHGlobal 正在分配比预期更多的内存

标签 c# c++ memory-management

我正在使用 Marshal.AllocHGlobal C# 方法为 IntPtr 分配内存,然后复制 byte[] 的内容:

byte[] clientIpAddr = System.Text.Encoding.ASCII.GetBytes("127.0.0.1")
IntPtr client_ipAddr_p = IntPtr.Zero;
ipAddress_p = Marshal.AllocHGlobal(clientIpAddr.Length);
Marshal.Copy(clientIpAddr, 0, ipAddress_p, clientIpAddr.Length);

然后我将指针传递给 C++ 外部库,该库接收我的变量,如下所示:

int open_socket(char *clientIpAddr_p)
{
    <open a socket>
}

根据AllocHGlobal的定义,它最终可以保留比预期更多的内存(我可以保证,因为我现在正在遭受它)。问题是我需要我的 IntPtr 具有我所请求的大小,因为我需要准确的 IP 才能随后打开套接字。

是否有更好的方法来分配外部内存以确保 char * 拥有正确的 IP?

最佳答案

Marshal.AllocHGlobal 分配的内存量超过指定的内存量并不是问题。您的代码遇到了一个不同的且很可能是致命的问题。

open_socket(char *clientIpAddr_p) 需要一个指向 C 风格 null-terminated string 的指针(也称为 NUL 终止字符串、零终止字符串或 ASCIIZ)。但是,您的 C# 代码创建一个缓冲区并用字符串字符/字节填充它,而不用空字符终止它。当在内存中(从指针给定的地址开始)搜索丢失的空字符时,这很可能会使 open_socket 函数崩溃或出现异常行为。

可能的修复方法相当简单:分配大小为 clientIpAddr.Length + 1 的缓冲区,以考虑终止空字符。必须显式设置零终止符(空字节),因为Marshal.AllocHGlobal不会用空字节初始化/填充分配的缓冲区。由于我们在这里处理的是 ASCII/ANSI 字符串,因此空字符只是一个值为 0 的字节。

byte[] clientIpAddr = System.Text.Encoding.ASCII.GetBytes("127.0.0.1")
IntPtr client_ipAddr_p = Marshal.AllocHGlobal(clientIpAddr.Length + 1);
Marshal.Copy(clientIpAddr, 0, ipAddress_p, clientIpAddr.Length);
Marshal.WriteByte(client_ipAddr_p, clientIpAddr.Length, 0);


好吧,忘掉我刚刚写的代码吧。 ;-)

为什么?因为有一个更简单的“一站式”解决方案来解决该问题,使您免于手动分配和填充 C 样式空终止字符串缓冲区的麻烦:Marshal.StringToHGlobalAnsi方法,它将直接将带有 IP 地址的 .NET 字符串转换为相应的 C 样式以 null 结尾的 ANSI 字符串。

string ipAddress = "127.0.0.1";
IntPtr client_ipAddr_p = Marshal.StringToHGlobalAnsi(ipAddress);

(除非open_socket函数需要clientIpAddr_p指向的字符串缓冲区在调用它后继续存在,否则使用Marshal.FreeHGlobal<释放分配的缓冲区 调用 native 函数后的方法,无论缓冲区是使用 Marshal.AllocHGlobal 还是 Marshal.StringToHGlobalAnsi 分配的。)

关于c# - Marshal.AllocHGlobal 正在分配比预期更多的内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56307553/

相关文章:

java - Spring Boot应用程序内存消耗

c - 如何在main()之外使用 `malloc`?

c# - 为什么我需要 "new"来进行锯齿状数组初始化?

c# - 查询Json如何获取must数组内的元素

c# - 尝试在 C# 中运行 powershell 脚本

c++使用冒泡排序自定义排序 vector

c++ - 循环缓冲区重置内存?

c++ - 为什么析构函数挂了

swift - 如果传递很多,Swift 中的结构会导致内存问题吗?

c# - Bitwise Shift - 在 C#.net 与 PHP 中获得不同的结果