为什么协程占用内存比线程更少?有栈协程为何仍更省内存?
协程被称为“轻量级线程”:内存占用更低的核心原因
很多人疑惑,既然有栈协程也有独立栈,为啥内存占用比线程低?核心在于线程(尤其是内核线程)包含大量协程不需要的内核态和用户态开销:
一、内核态的额外存储开销
线程是操作系统直接管理的内核对象,每个线程都要占用内核空间的额外资源:
- 内核栈:每个线程都有独立的内核栈(通常几KB到几十KB),用于处理系统调用、中断时保存内核态的寄存器上下文。协程是用户态调度的,完全不需要内核栈,所有上下文都在用户进程空间内。
- 线程控制块(TCB):操作系统需要维护每个线程的TCB,里面包含优先级、调度状态(就绪/阻塞/运行)、信号掩码、进程资源引用(比如文件描述符表、内存映射表的关联信息)、调度队列指针等大量元数据。这些元数据都存在内核空间,占用的内存远大于协程在用户态维护的简单调度信息(比如仅保存程序计数器、栈指针、少量寄存器)。
二、用户态的内存利用率差异
即使只看用户态的栈,线程和有栈协程也有明显区别:
- 栈的大小与分配方式:线程的用户栈通常是固定的大尺寸(比如Linux默认8MB),并且提前占用虚拟内存空间(物理内存按需分配,但虚拟地址会被预留)。而有栈协程的栈初始尺寸极小(比如Go的goroutine初始栈仅2KB),还能动态扩容/缩容,内存利用率远高于线程。
- 线程局部存储(TLS):每个线程都有独立的TLS区域,用于存储线程局部变量,操作系统需要维护TLS的映射和管理结构。协程的局部变量直接存在自己的栈中,不需要额外的TLS开销(除非语言实现刻意添加,但并非必需)。
三、调度切换的间接内存开销
线程切换需要陷入内核态,除了保存/恢复大量寄存器,还要刷新TLB(翻译后备缓冲器),这会导致内核栈的临时内存占用增加,同时触发更多的内存页交换。而协程切换完全在用户态完成,只需要保存少量关键寄存器(程序计数器、栈指针等),几乎没有额外的内存开销。
内容的提问来源于stack exchange,提问作者DiplomateProgrammer
相关产品推荐
相关产品推荐

