java 递归速度和内存

通常来说,java递归函数运行一般比循环函数慢,有时候甚至是一倍的差距,看下面的代码

public class RecursiveCall {
    public static void main(String[] args) {
        int total = 0;
        int first = 100;
        for (int x = 0; x < first; x++) {
            int n = 1000000;
            long start = System.currentTimeMillis();
            for (int i = 0; i < n; i++) {
                r(10);
            }
            total += (System.currentTimeMillis() - start);
        }
        System.out.println("average:" + total / first);

    }

    public static int r(int x) {
        if (x == 1) return 1;
        return x * r(x - 1);
    }

    public static int l(int n) {
        int result = 1;
        for (int i = 1; i <= n; i++) {
            result *= i;
        }
        return result;
    }
}

测试结果如下

次数循环平均递归速度比
111818
10016正无穷
100015正无穷
1000015正无穷
10000011正无穷

虽然不知道为什么循环函数平均是0,但是,目测应该是jvm做了某些优化,而我不知道,同时,我们看jvm消耗,发现一个小小的测试方法,却消耗了大量的内存
这里写图片描述

当循环10000次的时候,内存消耗大概为6M,这对于一个小小的计算问题,消耗算是时分巨大的。为什么会消耗如此多的内存,我们需要看看java 递归时的内存stack frame中的变化情况。进入idea的debug模式,

代码是最简单的递归

 public static void main(String[] args) {
        int result = r(10);
        System.out.println(result);
    }

这里写图片描述
这是刚进入main函数的时候的stack frame的情形,为了更加简化的显示我们只截图frame,就是最左边两个(frame + variable)。

第一个递归。
这里写图片描述

第2个递归。
这里写图片描述

第9个递归:
这里写图片描述
我们可以很清楚的看到,对于一个递归来说,它需要调用自己10次(最后一次debug不显示),知道最后一次才会返回结果,同时抛出这个stack frame,可以看见,在一个简单的方法中,这里消耗了10倍(仅仅这个例子)的内存,这增加了9倍的消耗,这是很难接受的。

时序图(也许不合适),在终止条件前,所有的自我调用都会消耗一个stack frame,如果自我调用次数多的话,那么,那是非常容易造成内存溢出的。

这里写图片描述

综上所述,递归一般是不被推荐的,当然,适当的利用递归的确可以简化代码,却是在好好思考之后做出的决定。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值