Java中的递归调用
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中的递归调用的更多相关文章
- Java中通过递归调用删除文件夹下所有文件
摘自 : http://blog.sina.com.cn/s/blog_79333b2c0100xiu4.html import java.io.File; public class FileTest ...
- Java中的递归运算
Java中的递归运算是一种在自己的方法内部调用自己的方法 递归的设计思想是:把一个复杂的问题,分解为若干个等同的子问题,重复执行,直到之问题能够简单到直接求解,这样复杂的问题就得以解决. 递归运算有两 ...
- 2018.3.31 java中的递归
java中的递归 1.概念 定义一个方法时,出现本方法调用本方法的过程,称之为递归 2.特点 必然有一个边界条件 使用递归代码往往更简洁,可读性强 3.什么时候使用递归 n的阶乘和n的累加定义 f(n ...
- 尾递归 递归函数中,递归调用是整个函数体中最后的语句,且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归,空间复杂度是O(1)
什么是递归深度 递归深度就是递归函数在内存中,同时存在的最大次数. 例如下面这段求阶乘的代码: Java: int factorial(int n) { if (n == 1) { return 1; ...
- Java中是否可以调用一个类中的main方法?
前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...
- java 中使用ajax调用后台方法注意事项
java 中使用ajax调用后台方法注意事项,后台方法一定要加@ResponseBody jQuery.validator.addMethod("checkRuleName",fu ...
- 【笔试题】Java 中如何递归显示一个目录下面的所有目录和文件?
笔试题 Java 中如何递归显示一个目录下面的所有目录和文件? import java.io.File; public class Test { private static void showDir ...
- JAVA中方法的调用主要有以下几种
JAVA中方法的调用主要有以下几种: 1.非静态方法 非静态方法就是没有 static 修饰的方法,对于非静态方法的调用,是通过对 象来调用的,表现形式如下. 对象名.方法() eg: public ...
- java基础06 Java中的递归
一.递归是指直接或间接地调用自身. 二.递归的注意事项: A:要有出口,否则就是死递归 B:次数不能过多,否则内存溢出 C:构造方法不能递归使用 三.举例子 递归 ...
随机推荐
- CodeForces731-C.Socks-并查集
C. Socks time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...
- 微信小程序监听input输入并取值
小程序的事件分为两种,冒泡和非冒泡事件,像<form/>的submit事件,<input/>的input事件,<scroll-view/>的scroll事件等非冒泡 ...
- QQ群友在线/离线,如何测试?
上篇文章『QQ好友在线/离线,如何测试?』针对即时通讯的"状态"进行了分析和总结,主要说到了QQ好友在线/离线实现方案,测试过程中需要注意的测试点. 针对好友状态实时性的要求需要使 ...
- TP5使用phpmailer实现邮件发送
1.从github下载PHPMailer,在vendor目录中新建文件夹phpmailer,将压缩包中的class.phpmailer.php和class.smtp.php复制到phpmailer中, ...
- ceil与intval区别
float ceil(float value)ceil返回不小于value的最小整数,返回值仍是float型 int intval ( mixed value [, int base]) int ...
- phpmyadmin设置密码,不用登录直接进入
版权声明:本文为博主原创文章,未经博主允许不得转载. 1.config.sample.inc.PHP改为config.inc.php 2.加入或更改代码: [php] view plain copy ...
- 怎样实现给DEDE的栏目增加栏目图片(1)
http://www.genban.org/news/dedecms-7577.html 前两天用DEDE做二次开发的时候,遇到一个问题,领导让给每个栏目增加一个栏目图片的功能,网上找了些东西,结合自 ...
- Html5+js测试题【完整版】
一.闭包的理解:使用闭包主要是为了设计私有的方法和变量.闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露.闭包三个特性: 1.函数嵌套函数 ; 2 ...
- Jupyter notebook入门
Jupyter notebook入门 [TOC] Jupyter notebook 是一种 Web 应用,能让用户将说明文本.数学方程.代码和可视化内容全部组合到一个易于共享的文档中. Jupyter ...
- java开发常用jar包
mail.jar与activation.jar 里面包含了activation.jar和mail.jar两个包.通过里面的类的调用便可以达到发送电子邮件的目的 commons-beanutils.ja ...