java 虚拟机栈,在此规定了两种异常情况: 1.线程请求栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常; 2.如果虚拟机栈可以动态扩展,当扩展是无法申请到足够的内存时会抛出OutOfMemoryError异常. 第一种情况示例分析 code: import java.util.ArrayList; import java.util.List; public class TailRecursionTest2 { public static void main(String[] args) { TailRecursionTest2 t = new TailRecursionTest2(); t.a(0); } public void a(int j) { System.out.println(j); j++; if (j == 10000) return; List list = new ArrayList<Integer>(100000); // 对list进行处理 list = null; //gc友好 a(j); } } 分析: 线程请求栈的深度大于虚拟机所允许的深度,将抛出StackOverflowError异常, 你肯定想到了,是不是重复创建list这个大集合引起的呢?它不 是局部变量吗?怎么也会溢出?是的,list是局部变量,在a的方法栈里引用着,指向heap上的大对象,更关键的问题在于,java是没有尾递归 优化的,递归方法是不会使用同一个栈帧,每一次递归调用,都将压入新的栈帧,并且这个栈帧上又new了一个list变量,引用着heap上新的一 个大集合。随着栈深度的增加, jvm里维持着一条长长的方法调用轨迹以便你能回来,在方法没有返回之前,这些list变量一直被各自的栈帧引 用着,不能被GC,你说,能不OOM吗? 也许,你想到了个补救方法来挽救程序2,就是每次在处理完list后,我把它设置为null,不让栈帧继续引用着它,咱编写对gc友好的代码,这 不就行了,试试: 总结:在java里,递归最好咱还是别用,老老实实地while、for;就算递归了,最好递归方法不要new太大的对象,除非你能确定递归的深度不 是那么大,否则OOM和堆栈溢出的阴影将笼罩着你。 第二种情况分析:·[未完。。。]