Ubuntu下C# .NET中非托管内存Span使用不符合预期问题
非托管内存Span调用ToArray失效问题解析
问题代码
const int nbytes = 100; var ptr = Marshal.AllocHGlobal(nbytes); try { var ptrToInt = (int*)ptr.ToPointer();// 需将void*转换为int* Span<int> span = new Span<int>(ptrToInt, nbytes >> 2); span.Fill(42); int cap = nbytes >> 2; for (int i = 0; i < cap; i++) { Console.WriteLine(span[i]); } Console.WriteLine(",", string.Join(",", span.ToArray())); // 此处未正常输出,原因未知? } finally { Marshal.FreeHGlobal(ptr);// 最终必须释放已使用的内存 }
问题核心原因
你遇到的根本不是Span<T>.ToArray()方法的问题,而是Console.WriteLine的调用方式错误:
Console.WriteLine(string format, params object?[] args)方法中,第一个参数是格式字符串,需要包含对应参数的占位符(比如{0})才能输出第二个参数的内容。- 你传入的格式字符串是
",",没有任何占位符,所以第二个参数(span.ToArray()的拼接结果)会被忽略,自然看不到输出。
修正这个调用即可看到ToArray()的正常结果:
Console.WriteLine("{0}", string.Join(",", span.ToArray())); // 或者直接简化为:Console.WriteLine(string.Join(",", span.ToArray()));
非托管内存Span的注意事项
虽然这次问题和非托管内存无关,但使用非托管内存创建Span<T>时确实有几个关键注意点:
- 内存生命周期管理:非托管内存不会被GC自动回收,必须手动调用
Marshal.FreeHGlobal或对应释放方法,否则会造成内存泄漏。 - 内存对齐要求:
Span<T>要求内存地址符合T类型的对齐规则,比如int需要4字节对齐。如果非托管内存的起始地址不满足对齐要求,可能引发性能问题甚至运行时错误。 - 类型转换安全性:将非托管指针转换为
T*时,必须确保内存区域的类型和T匹配,否则会导致数据读取错误或未定义行为。 - 内存访问权限:非托管内存可能存在访问权限限制,比如只读内存,写入操作会引发异常。
内容的提问来源于stack exchange,提问作者Mehdi Mowlavi
相关产品推荐
相关产品推荐

