You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 00:31:06