Java中不合理的使用递归调用,可能会致使栈内存溢出,这点是须要注意的。java
java将为每一个线程维护一个栈,栈里将为每一个方法保存一个栈帧,栈帧表明了一个方法的运行状态。 也就是咱们常说的方法栈。最后一个为当前运行的栈帧。数据库
那么每一次方法调用会为新调用方法的生成一个栈帧,保存当前方法的栈帧状态,栈帧上下文切换,切换到最新的方法栈帧。数组
在递归和循环之间选择时,应该优先选择的是循环而非递归,特别是要避免深度的递归。函数
关于递归还须要了解的是尾递归调用,尾递归调用是能够被进行优化的。优化
尾调用指的是一个方法或者函数的调用在另外一个方法或者函数的最后一条指令中进行。下面定义了一个foo()函数做为例子:spa
int foo(int a) { a = a + 1; return func(a); }
尾调用,不仅是尾递归,函数调用自己均可以被优化掉,变得跟goto操做同样。这就意味着,在函数调用前先把栈给设置好,调用完成后再恢复栈的这个操做(分别是prolog和epilog)能够被优化掉。线程
函数式语言的开发人员常常使用递归,因此大多数函数式语言的解释器都会进行尾调用的优化。可是在Java中使用深度的递归必定要很是的当心,不然颇有可能会致使栈溢出的发生。code
下面是不合理使用递归的例子:对象
package test; public class RecursiveTest { /** * 递归实现 * * @param n * @return */ public static double recursive(long n) { if (n == 1) { return Math.log(1); } else { return Math.log(n) + recursive(n - 1); } } /** * 非递归实现 * * @param n * @return */ public static double directly(long n) { double result = 0; for (int i = 1; i <= n; i++) { result += Math.log(i); } return result; } public static void main(String[] args) { int i = 5000000; long test = System.nanoTime(); long start1 = System.nanoTime(); double r1 = recursive(i); long end1 = System.nanoTime(); long start2 = System.nanoTime(); double r2 = directly(i); long end2 = System.nanoTime(); System.out.println("recursive result:" + r1); System.out.println("recursive time used:" + (end1 - start1)); System.out.println("non-recursive result:" + r2); System.out.println("non-recursive time used:" + (end2 - start2)); } }
JVM中可能致使内存溢出的其余缘由还包括: blog
如String s1 = "My name";
String s2 = "is";
String s3 = "xuwei";
String str = s1 + s2 + s3 +.........;这是会容易形成内存溢出的