- 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常
- 如果虚拟机栈可以动态扩展(当前大部分的 Java 虚拟机都可动态扩展,只不过 Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出 OutOfMemoryError 异常
单个线程下,无论是由于栈帧太大,还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是 StackOverflowError 异常,而不是OOM
如果不限于单线程,通过不断地建立线程的方式倒是可以产生内存溢出异常。自己可以创建多个线程,进行测试,但是:由于在Windows 平台的虚拟机中, Java 的线程是映射到操作系统的内核线程上的,所以多线程代码执行时有较大的风险,可能会导致操作系统假死
操作系统分配给每个进程的内存是有限制的,譬如 32 位的 Windows 限制为 2GB。虚拟机提供了参数来控制 Java 堆和方法区的这两部分内存的最大值。剩余的内存为 2GB(操作系统限制)减去 Xmx(最大堆容量),再减去 MaxPermSize(最大方法区容量),程序计数器消耗内存很小,可以忽略掉。如果虚拟机进程本身耗费的内存不计算在内,剩下的内存就由虚拟机栈和本地方法栈“瓜分”了。每个线程分配到的栈容量越大,可以建立的线程数量自然就越少,建立线程时就越容易把剩下的内存耗尽
动态栈通常有两种方法:Segmented stack和Stack copying。
Segmented stack可以简单理解成一个双向链表把多个栈连接起来,一开始只分配一个栈,这个栈的空间不够时,就再分配一个,用链表一个一个连起来。
Stack copying就是在栈不够的时候,分配一个更大的栈,然后把原来的栈复制过去。