Java中不合理的使用递归调用,可能会导致栈内存溢出,这点是需要注意的。

  

  java将为每个线程维护一个栈,栈里将为每个方法保存一个栈帧,栈帧代表了一个方法的运行状态。 也就是我们常说的方法栈。最后一个为当前运行的栈帧。

  那么每一次方法调用会为新调用方法的生成一个栈帧,保存当前方法的栈帧状态,栈帧上下文切换,切换到最新的方法栈帧。

  在递归和循环之间选择时,应该优先选择的是循环而非递归,特别是要避免深度的递归。

  

  关于递归还需要了解的是尾递归调用,尾递归调用是可以被进行优化的。

  尾调用指的是一个方法或者函数的调用在另一个方法或者函数的最后一条指令中进行。下面定义了一个foo()函数作为例子:

int foo(int a) {
a = a + 1;
return func(a);
}

  尾调用,不只是尾递归,函数调用本身都可以被优化掉,变得跟goto操作一样。这就意味着,在函数调用前先把栈给设置好,调用完成后再恢复栈的这个操作(分别是prolog和epilog)可以被优化掉。

  函数式语言的开发人员经常使用递归,所以大多数函数式语言的解释器都会进行尾调用的优化。但是在Java中使用深度的递归一定要非常的小心,否则很有可能会导致栈溢出的发生。

  

  下面是不合理使用递归的例子:

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中可能导致内存溢出的其他原因还包括: 

  • 引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;
  • 使用了大量的递归或无限递归(递归中用到了大量的建新的对象)
  • 使用了大量循环或死循环(循环中用到了大量的新建的对象)
  • 是否使用了向数据库查询所有记录的方法。即一次性全部查询的方法,如果数据量超过10万多条了,就可能会造成内存溢出。所以在查询时应采用“分页查询”。
  • 是否有数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放。会大量存储在内存中。
  • 是否使用了“非字面量字符串进行+”的操作。因为String类的内容是不可变的,每次运行"+"就会产生新的对象,如果过多会造成新String对象过多,从而导致JVM没有及时回收而出现内存溢出。

  如String s1 = "My name";

  String s2 = "is";

  String s3 = "xuwei";

  String str = s1 + s2 + s3 +.........;这是会容易造成内存溢出的

  

Java中的递归调用的更多相关文章

  1. Java中通过递归调用删除文件夹下所有文件

    摘自 : http://blog.sina.com.cn/s/blog_79333b2c0100xiu4.html import java.io.File; public class FileTest ...

  2. Java中的递归运算

    Java中的递归运算是一种在自己的方法内部调用自己的方法 递归的设计思想是:把一个复杂的问题,分解为若干个等同的子问题,重复执行,直到之问题能够简单到直接求解,这样复杂的问题就得以解决. 递归运算有两 ...

  3. 2018.3.31 java中的递归

    java中的递归 1.概念 定义一个方法时,出现本方法调用本方法的过程,称之为递归 2.特点 必然有一个边界条件 使用递归代码往往更简洁,可读性强 3.什么时候使用递归 n的阶乘和n的累加定义 f(n ...

  4. 尾递归 递归函数中,递归调用是整个函数体中最后的语句,且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归,空间复杂度是O(1)

    什么是递归深度 递归深度就是递归函数在内存中,同时存在的最大次数. 例如下面这段求阶乘的代码: Java: int factorial(int n) { if (n == 1) { return 1; ...

  5. Java中是否可以调用一个类中的main方法?

    前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...

  6. java 中使用ajax调用后台方法注意事项

    java 中使用ajax调用后台方法注意事项,后台方法一定要加@ResponseBody jQuery.validator.addMethod("checkRuleName",fu ...

  7. 【笔试题】Java 中如何递归显示一个目录下面的所有目录和文件?

    笔试题 Java 中如何递归显示一个目录下面的所有目录和文件? import java.io.File; public class Test { private static void showDir ...

  8. JAVA中方法的调用主要有以下几种

    JAVA中方法的调用主要有以下几种: 1.非静态方法 非静态方法就是没有 static 修饰的方法,对于非静态方法的调用,是通过对 象来调用的,表现形式如下. 对象名.方法() eg: public ...

  9. java基础06 Java中的递归

      一.递归是指直接或间接地调用自身. 二.递归的注意事项:             A:要有出口,否则就是死递归 B:次数不能过多,否则内存溢出 C:构造方法不能递归使用     三.举例子  递归 ...

随机推荐

  1. [bzoj1273] [BeiJingWc2008]序列

    一开始想拆位..但显然没法应对进位啊什么的. 所以维护每一个长度的后缀. 查询有多少个a&2^i>0,也就是长度为(i+1)的后缀里,值为2^i...2^(i+1)-1的数有多少个. 前 ...

  2. 2017多校第一套&&hdu6038 思维 数学

    链接  http://acm.hdu.edu.cn/showproblem.php?pid=6038 题意: 给你一个a序列,代表0到n-1的排列:一个b序列代表0到m-1的排列.问你可以找出多少种函 ...

  3. Django 用散列隐藏数据库中主键ID

    最近看到了一篇讲Django性能测试和优化的文章, 文中除了提到了很多有用的优化方法, 演示程序的数据库模型写法我觉得也很值得参考, 在这单独记录下. 原文的演示代码有些问题, 我改进了下, 这里可以 ...

  4. 解决get乱码

    也可以在tomcat中修改,但是每次配置tomcat中都得修改.容易忘记,还是图片这个方法最好,推荐

  5. p2p项目,自己期望太高了。

    在项目的进行中,主要牵扯到了一些安全方面的考虑,跟money相关的嘛,如果安全不考虑,你就惨了,一期呢,为了防止数据被篡改,主要对数据用dsa进行了签名,二期呢,考虑到das产生的字符串有可能太长,修 ...

  6. Dev中GridControl的导出Excel设置

    接上篇 Dev中GridControl的GridView 基本样式设置 上图: 导出部分的代码: /// <summary> /// 导出excel /// </summary> ...

  7. Angular 4+ HttpClient

    个人博客迁移至 http://www.sulishibaobei.com  处: 这篇,算是上一篇Angular 4+ Http的后续: Angular 4.3.0-rc.0 版本已经发布

  8. MySQL查询性能优化一则

    公司有一套Web系统, 使用方反馈系统某些页面访问速度缓慢, 用户体验很差, 并且偶尔还会出现HTTP 502错误. 这是典型的服务器端IO阻塞引发的问题,通过对访问页面的程序逻辑进行跟踪,发现问题应 ...

  9. django 编程小结

    1.增删改查 add obj = Obj(atr=atr..) obj.save() update: __dict__ 遍历 del: 根据id列表删除 query: 首次查询: 直接跳转至页面,前端 ...

  10. linux_DNS

    linux其配置文件 : /etc/resolv.conf nameserver 223.5.5.5 nameserver 223.6.6.6 # 这两个解析地址为阿里云解析地址,格式也是这样 什么是 ...