虚拟机栈和本地方法栈的分水岭是invokenative指令:此前由jvm管控栈帧分配(触发stackoverflowerror或outofmemoryerror),此后由操作系统接管(同样可能抛出两类错误)。

虚拟机栈和本地方法栈在字节码指令层面没有独立的分配指令,它们的资源申请完全由线程创建和方法调用行为隐式触发——分水岭不在指令本身,而在执行上下文是否进入 JVM 字节码解释/编译路径。
虚拟机栈分配失败由字节码调用链驱动
每当执行 invokestatic、invokevirtual、invokeinterface 或 invokespecial 指令时,JVM 必须为被调用方法创建新栈帧。该过程需满足两个前提:
- 当前线程的虚拟机栈仍有空间容纳新栈帧(含局部变量表、操作数栈等结构)
- 栈帧所需内存未超出单个线程的 -Xss 限额
若不满足,且调用深度已逼近上限(如无限递归中连续 invokevirtual),则抛出 StackOverflowError;若栈需动态扩展但宿主内存不足(如多线程争抢地址空间),则抛出 OutOfMemoryError: unable to create new native thread(注意:此 OOM 实际源于线程创建阶段,非某条字节码直接导致)。
本地方法栈溢出不经过任何字节码指令调度
本地方法(native method)通过 invokenative 指令发起调用,但该指令本身不分配本地方法栈空间——它只是向 JNI 环境发出一个“执行 C/C++ 函数”的信号。后续栈空间由操作系统线程库(如 pthread_create)按平台约定分配,与字节码解释器无关:
- 若 native 函数内部发生深度递归(如 C 层面的无限调用),崩溃发生在 OS 栈,JVM 捕获后统一映射为 StackOverflowError
- 若大量线程同时进入 native 方法且各自栈预留过大,OS 无法为新线程分配内核栈,则 JVM 在 java.lang.Thread.start() 的底层实现中收到 ENOMEM,最终抛出 OutOfMemoryError: unable to create new native thread
关键分水岭:控制权移交点是否脱离字节码引擎
判断依据非常明确:
- 所有 invoke*(除 invokenative)引发的栈帧增长,都处于 JVM 解释器或 JIT 编译器管控下,属虚拟机栈范畴
- invokenative 是唯一将控制权彻底交出的字节码指令;此后任何栈操作(包括分配、压栈、溢出)均由本地运行时接管,JVM 只负责错误回传
- 因此,即使同一段 Java 代码(如递归调用 native 方法),溢出根源也取决于:是 Java 层调用链过深(虚拟机栈),还是 native 层函数自身栈行为异常(本地方法栈)
不复杂但容易忽略:字节码里没有“分配栈”指令,只有“触发栈使用”的指令;真正的分水岭,是 invokenative 这道门——跨过去,就离开了 JVM 的字节码世界。











