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

线程栈超出分配限制时会怎样?为何我的.NET Core程序未报错?

线程栈分配限制疑问

我尝试理解线程栈分配限制,通过ulimit -s 50将栈限制设置为50KB后,运行了以下C#程序:

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var thread = new Thread(() => {
                DownloadImage();
            });

            thread.Start();
        
            Console.ReadKey();
        }

        private static async void DownloadImage()
        {
            using var client = new HttpClient();
        
            using var file = await client.GetStreamAsync("some url with 1 MB file", CancellationToken.None);
        
            using var memoryStream = new MemoryStream();
        
            await file.CopyToAsync(memoryStream);
        
            var memoryBytes = memoryStream.ToArray();
            Console.WriteLine($"File has {memoryBytes.Length} bytes.");
        }
    }
}

原本以为memoryBytes变量会占用线程栈的1MB内存,触发栈溢出异常,但程序运行正常,没有抛出异常。这是为什么?是不是.NET Core在运行时修改了该限制?


问题解析
  • memoryBytes的实际存储位置不在栈上:memoryBytes是字节数组,属于引用类型,它的数据内容存储在托管堆中,线程栈上仅保存了指向这个数组的引用(64位系统占8字节,32位系统占4字节),这点内存远低于50KB的栈限制,自然不会触发溢出。

  • 异步方法的执行逻辑不依赖原线程栈:DownloadImage是异步方法,执行到await关键字时,当前线程会被释放回线程池;后续IO操作完成后,回调逻辑会由线程池重新调度其他线程执行,整个过程和你创建的那个线程的栈没有关联,不会占用它的栈空间。

  • .NET不会修改系统栈限制:你通过ulimit设置的50KB栈限制是有效的,但.NET的内存管理规则中,栈仅用于存储方法调用栈帧、值类型局部变量、引用类型的引用,像大数组、对象实例这类大块内存都会分配在托管堆上,和栈限制无关。

内容的提问来源于stack exchange,提问作者justin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 22:55:19