c# 在 .NET 中,一个进程最多可以创建多少个线程

来源:这里教程网 时间:2026-02-21 17:39:24 作者:

线程数受操作系统和内存限制,不是 .NET 硬编码上限

.NET 本身不设固定线程数量上限,

ThreadPool
默认最大线程数由
ThreadPool.GetMaxThreads
返回,但这个值只是线程池的“软限制”,实际能创建多少个
Thread
实例,取决于 Windows(或 Linux/macOS)能为该进程分配多少栈空间和内核对象。

每个线程默认占用 1MB 栈空间,内存很快见底

在 Windows 上,.NET 的

Thread
默认栈大小是 1 MB(x64 进程),哪怕只调用
new Thread(() => {}).Start()
,也会立即向进程地址空间申请这块保留内存(commit 按需)。32 位进程用户态地址空间仅约 2GB,理论上撑不过 2000 个线程;64 位进程虽大得多,但物理内存和页表开销会先成为瓶颈。常见现象是:创建几百个线程后,
OutOfMemoryException
Thread.Start()
抛出
InvalidOperationException
(内部触发
ERROR_NOT_ENOUGH_MEMORY
)。

Thread
构造时可通过
new Thread(..., stackSize)
指定更小栈(如
256 * 1024
),但低于 128KB 可能导致 StackOverflow
频繁创建/销毁线程比复用
ThreadPool
Task
开销大得多,且易触发 GC 压力
Windows 内核对每个进程的线程句柄数也有默认限制(通常 2000–4000),可通过
SetProcessInformation
调整,但极少需要

别硬扛线程数,改用异步 I/O 和 Task 调度

真正需要“高并发”的场景(如万级连接的服务器),几乎从不依赖大量

Thread
实例。正确做法是:用
async/await
+
SocketAsyncEventArgs
(或
System.Net.Sockets.Socket
的异步方法),让单线程处理数百连接;CPU 密集任务则交由
Task.Run
并依赖
ThreadPool
自动伸缩(其最大线程数默认为
Environment.ProcessorCount * 100
,但会按负载动态调整)。

var tasks = Enumerable.Range(0, 10000)
    .Select(_ => Task.Run(() => HeavyComputation()))
    .ToArray();
await Task.WhenAll(tasks); // 实际并发执行数远小于 10000,由线程池控制

检查当前限制和实际使用量的方法

运行时可快速验证当前环境约束:

查线程池上限:
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads)
查已启动线程数(粗略):
Process.GetCurrentProcess().Threads.Count
(注意:包含调试器、GC、JIT 等后台线程)
观察私有字节(Private Bytes)增长:每新增一个默认栈线程,进程内存上升约 1MB(保留区)

真要突破几百线程,先确认是否误用了同步阻塞模型——这是绝大多数“需要更多线程”诉求的根源。

相关推荐