在java语言中,使用递归调用时,如果过多的调用容易造成java.lang.StackOverflowError即栈溢出和程序执行过慢。这是一个潜在Bug和影响程序执行效率问题,需要谨慎使用。
 
下面先看造成java.lang.StackOverflowError即栈溢出问题:
public class RecursionTest
{ public static void recursion(int totalTimes,int time)
{
if(totalTimes > 1)
{
System.out.println("这是第 " + time + "次调用!");
totalTimes--;
time++;
recursion(totalTimes, time);
}
else
{
System.out.println("调用结束,共调用了" + time + "次");
return;
}
} public static void main(String[] args)
{
int totalTimes = 1000000;
int time = 1;
long startTime = System.currentTimeMillis();
System.out.println("嵌套调用起始时间:" + startTime);
recursion(totalTimes, time);
System.out.println("嵌套调用结束时间:" + System.currentTimeMillis());
System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));
System.out.println("------------------------------------------------------------");
} }

修改“totalTimes”,当到达一定值时,报如下错误:

在开发时,要注意避免该问题,特别是递归过多调用时,最好改为for或者whlie来代替。
如下cycle()方法:
	public static void cycle(int totalTimes, int time)
{
if(totalTimes > 1)
{
System.out.println("这是第 " + time + "次调用!");
}
else
{
System.out.println("调用结束,共调用了" + time + "次");
}
}

代替recuresion()方法:

public static void recursion(int totalTimes,int time)
{
if(totalTimes > 1)
{
System.out.println("这是第 " + time + "次调用!");
totalTimes--;
time++;
recursion(totalTimes, time);
}
else
{
System.out.println("调用结束,共调用了" + time + "次");
return;
}
}

再看一下对程序执行效率的影响:
仍然使用上面的例子,分别cycle()方法和在main()方法中加入如下代码:
		startTime = System.currentTimeMillis();
System.out.println("循环调用起始时间:" + startTime);
for (int index = totalTimes; index > 0; index--)
{
cycle(index, time);
time++;
}
System.out.println("循环调用结束时间:" + System.currentTimeMillis());
System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));
System.out.println("--------------------

整个代码如下:

public class RecursionTest
{ public static void recursion(int totalTimes,int time)
{
if(totalTimes > 1)
{
System.out.println("这是第 " + time + "次调用!");
totalTimes--;
time++;
recursion(totalTimes, time);
}
else
{
System.out.println("调用结束,共调用了" + time + "次");
return;
}
} public static void cycle(int totalTimes, int time)
{
if(totalTimes > 1)
{
System.out.println("这是第 " + time + "次调用!");
}
else
{
System.out.println("调用结束,共调用了" + time + "次");
}
} public static void main(String[] args)
{
int totalTimes = 100000;
int time = 1;
long startTime = System.currentTimeMillis();
System.out.println("嵌套调用起始时间:" + startTime);
recursion(totalTimes, time);
System.out.println("嵌套调用结束时间:" + System.currentTimeMillis());
System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));
System.out.println("------------------------------------------------------------"); startTime = System.currentTimeMillis();
System.out.println("循环调用起始时间:" + startTime);
for (int index = totalTimes; index > 0; index--)
{
cycle(index, time);
time++;
}
System.out.println("循环调用结束时间:" + System.currentTimeMillis());
System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));
System.out.println("------------------------------------------------------------");
} }
 
分别测试totalTimes为500,1000,3000对比结果:
 
500次:
1000次:


 
3000次:
 
以下是从网络上摘抄的:
根本原因是这样的,对于每一个线程,都有一个java栈 ,当有一个方法被调用的时候,会产生一些跟这个方法相关的信息,如方法名,参数,中间变量等等,这些叫做栈帧 ,当一个方法执行完毕  这个栈帧才会从栈顶pop掉  你递归的话  会一直向栈里push栈帧  而这个java栈是有一定的长度或深度的,当栈满了,无法再进行push的时候 就出现你上面的异常了,解决办法的话 就不要用递归操作 改用for 而且平时也不建议用递归的,效率太低了 .

栈溢出了,JVM依然是采用栈式的虚拟机,这个和C和Pascal都是一样的。函数的调用过程都体现在堆栈和退栈上了。你调用构造函数的“层”太多了,以致于把栈区溢出了。  
通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要1K的空间(这个大约相当于在一个C函数内声明了256个int类型的变量),那么栈区也不过是需要1MB的空间。通常栈的大小是1-2MB的。通常递归也不要递归的层次过多,很容易溢出.  

 
对java.lang.StackOverflowError的分析:  
原因:运行一个程序,JVM会开辟一块内存空间去储存程序进行时的某些信息,当程序运行时需要储存的信息超过了分配的空间,就会出现那样的问题.比如死循环,  
解决:首先从程序代码优化方面着手,检查是否有死循环、递归等程序,如果有,修正、优化相关代码。  

Java递归调用改成非递归的更多相关文章

  1. 深度优先搜索(DFS)递归形式改为非递归形式

    DFS将递归改为非递归这个方法的需求来自于一道三维积木组合的题目,还在苦苦调试中,暂且不提. 普通的认识对于递归向非递归的转化无非是使用栈,但是结合到深度搜索如何将栈很好利用,如何很好保存现场,都不是 ...

  2. C# Windows Phone 8 WP8 开发,将WebClient的DownloadStringCompleted事件改成非同步的awiat方法。

    原文:C# Windows Phone 8 WP8 开发,将WebClient的DownloadStringCompleted事件改成非同步的awiat方法. 一般我们在撰写Windows Phone ...

  3. Java 递归、尾递归、非递归、栈 处理 三角数问题

    import java.io.BufferedReader; import java.io.InputStreamReader; //1,3,6,10,15...n 三角数 /* * # 1 * ## ...

  4. Java 递归、尾递归、非递归 处理阶乘问题

    n!=n*(n-1)! import java.io.BufferedReader; import java.io.InputStreamReader; /** * n的阶乘,即n! (n*(n-1) ...

  5. java创建二叉树并实现非递归中序遍历二叉树

    java创建二叉树并递归遍历二叉树前面已有讲解:http://www.cnblogs.com/lixiaolun/p/4658659.html. 在此基础上添加了非递归中序遍历二叉树: 二叉树类的代码 ...

  6. java只http改成https访问

    目录 生成keystore文件 修改tomcat中的server.xml文件 配置浏览器 生成keystore文件: 1.在tomcat的bin 目录下输入命令:keytool -genkeypair ...

  7. 如何由jdk的安装版本改成非安装版本

    背景. 官网一般只提供windows下的exe文件,不提供zip打包文件.有些不愿意使用安装版本. 解决方法 本文以windows 7下安装jdk-6u35-windows-x64.exe为例说明 1 ...

  8. JAVA 遍历文件夹下的所有文件(递归调用和非递归调用)

    JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...

  9. [复习] JAVA 遍历目录 (递归调用和非递归)

    JAVA 遍历文件夹下的所有文件(递归调用和非递归调用) 1.不使用递归的方法调用. public void traverseFolder1(String path) { int fileNum = ...

随机推荐

  1. hdu acm 1114 Piggy-Bank 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1114 题目意思:给出一个空的猪仔钱ang 的重量E,和一个装满钱的猪仔钱ang 的重量F你,实质上能装 ...

  2. hdu-5720 Wool(区间并+扫描线)

    题目链接: Wool Time Limit: 8000/4000 MS (Java/Others)     Memory Limit: 262144/262144 K (Java/Others) Pr ...

  3. [Selenium] 使用Firefox Driver 示例

    //导入Selenium 库和FirefoxDriver 库 package com.learningselenium.simplewebdriver; import org.openqa.selen ...

  4. [Selenium] Automation Test Manual(Selenium)

    http://www.cnblogs.com/puresoul/p/3483055.html http://www.360doc.com/content/14/0913/10/13497042_409 ...

  5. Burpsuite实验(二)

    一.这次我们使用一下burpsuite的代理拦截功能. 图中的proxy是代理的选项,其中intercept是拦截的功能,在浏览器中请求的包,都经过它. 这是打开拦截时候的状态.forward是通过此 ...

  6. pymssql读取varchar字段中文显示乱码的问题分析

    问题 用python的pymssql模块读取旧业务系统后台SQL Server 2000数据库展示数据为乱码 开发环境 操作系统:windows 8 数据库 MS SQL Server 2000,默认 ...

  7. 通过链接将JSP页面中一变量传到另一JSP界面中

    A.jsp 发送 <a herf="B.jsp?name=<%=name%>">传递到B页面</a> B.jsp  接收 <%String ...

  8. pythonchallenge 2

     pythonchallenge是一个很有意思的学习python的网站,通过用程序解开一个谜,可以进入到下一个level,总共有几十个level,网址是http://www.pythonchallen ...

  9. ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 22. 再讲Tag Helpers

    深入的讲Tag Helpers 加载app下面的所有的文件夹以及各自文件夹下面所有的js文件. exclude是排除掉Services文件夹和其下面的子文件夹 使用cdn加载远程的js文件 找hidd ...

  10. Codeforces 550B 【暴力】

    题意: 有n个数字, 要求在这n个数中选出至少两个数字, 使得它们的和在L,R之间,并且最大的与最小的差值要不小于x 思路: 撒比了啊... 根据状态的话一共也就是2^15-直接暴力,二进制的小魅力还 ...