为何Java 21虚拟线程内存占用比平台线程更低?
平台线程与虚拟线程的内存开销差异解析
虚拟线程切换也需要保存上下文,但方式完全不同
虚拟线程切换时确实要保存当前的执行上下文(比如程序计数器、局部变量、调用栈状态),但和平台线程的切换逻辑、内存占用不在一个量级:
- 平台线程是内核级切换,需要完整保存/恢复内核态上下文(寄存器集合、内核栈、页表映射等),这些数据存在内核空间,每个线程都要占用额外的内核内存;
- 虚拟线程是用户级切换(以Java为例,由JVM负责调度),仅需保存用户态的执行上下文,数据全部在用户空间,占用内存极少,且切换过程完全不涉及内核操作。
内存占用差异的核心来源
1. 栈空间的本质区别
- 平台线程:栈是固定大小的物理内存块,通常默认分配12MB(不同语言/系统略有差异),创建时直接预留整块内存,哪怕实际只用了几KB,剩余空间也无法被其他线程复用。10000个平台线程的栈总开销就是1020GB,远超普通应用的内存上限,必然溢出。
- 虚拟线程:栈是按需分配、可动态伸缩的虚拟栈,初始仅分配几KB空间,执行过程中需要更多栈空间时再自动扩容,闲置或栈收缩时还能释放内存给其他使用。10000个虚拟线程的初始栈总开销仅几十MB,即使运行中扩容,总内存也远低于同数量的平台线程。
2. 内核级资源的额外开销
平台线程是操作系统的原生线程,每个线程对应一个内核线程,操作系统需要为其维护大量内核级数据结构:
- 线程控制块(TCB):存储线程ID、优先级、状态、调度信息等;
- 内核栈:用于内核态执行时的调用栈;
- 信号处理、锁状态等其他内核资源。
这些内核级资源的内存开销是每个平台线程都必须承担的,且系统能创建的原生线程数量受内核限制(比如Linux默认上限通常在几千到一万左右)。
而虚拟线程完全由用户态 runtime(如JVM)管理,内核看不到虚拟线程的存在,仅需维护承载虚拟线程的少量载体线程(数量通常等于CPU核心数),所有虚拟线程的调度、上下文维护都在用户态完成,不需要消耗任何内核级额外资源。
上下文维护的共性与差异
- 两者都需要维护应用相关的执行上下文(局部变量、方法调用栈等),但存储方式不同:平台线程存在固定的物理栈,虚拟线程存在动态的虚拟栈。
- 平台线程多了内核态上下文的维护开销,这部分是虚拟线程完全没有的,也是虚拟线程更轻量的关键因素之一。
为什么10000个虚拟线程不会内存溢出?
因为虚拟线程的总内存开销由动态伸缩的栈 + 用户态上下文数据组成,10000个实例的总内存通常在几百MB以内,远低于普通应用的内存阈值;而10000个平台线程仅栈空间就占用十几GB,再加上内核级资源开销,直接超出内存上限导致溢出。
内容的提问来源于stack exchange,提问作者user1189332
相关产品推荐
相关产品推荐

