douchenzhan3050 2014-01-27 11:01
浏览 28

递归会导致内存使用量激增

function rec_func($x) {   
   echo $x;
   if ($x < 1000) {
      $x++;
      rec_func(&$x);
   }
}

This is not the actual recursive function, that I am going to be using for my PHP script. Just like this example, my real function works perfectly fine, up to the point where I start examining how much memory is it using.

If I loop this function, say, a 100 times, nothing bad happens. The used memory in each iteration stays the same. But If I loop 1000 times and more, at one point this function will start consuming more memory than before, right up to the last iteration.

The amount of spikes seem to depend on how big is the variable I give it, and how many iterations it goes through, but I can't be certain. And this is where the problem begins. This function will start consuming more memory just once in a 1000 times. My function, however, does this every 150 or so times in 1000 iterations, and the worst thing is that MY function may have to loop even more times than that.

This made me curious, because the obvious thing to do would be to use a traditional loop instead (which I have done), but I really want to understand why is this happening, and if it can be avoided.

P.S. note that I'm using a real variable only in the first iteration and all of the iterations following it are using a reference, to preserve memory. Thanks in advance.

  • 写回答

1条回答 默认 最新

  • dongliufa6380 2014-01-27 11:40
    关注

    (correct me if I am wrong). I think, it is related with your PHP module memory handling: It does reserve some memory when it starts running (if it is used as CGI for example, or you call it from a command prompt).

    Every time when you start a recursion, it will do two things basically:

    Before calling the next level of recursion, saves the current status to the call stack. If you are not manipulating with references, then the variable data as well, with the current stack state. As long as the reserved memory is enough, your memory consumption will not be increased, but when you run out of memory, a new bunch of memory will be reserved, in order if more will be needed. It means the following:

    function rec_func($x) {   
       echo $x;
       if ($x < 1000) {
          $x++;
          rec_func($x);
       }
    }
    

    This will have a significant bigger memory usage, as every time a recursion occures, there will be an extra line in the stack, and you will create an extra $x in the memory to store it's current state, in order to reserve the value when the recursion get's back to the current stack call.

    The following lines will get rid of the memory usage problem - it manipulates with variable references (obviously ruins the functionality in this case:

    function rec_func(&$x) {   
       echo $x;
       if ($x < 1000) {
          $x++;
          rec_func($x);
       }
    }
    

    (your original code causes fatal error due to call-time reference passing).

    In case if you want to reduce the memory usage, you should (or can) use references in the function declaration for variables, which will not change during the recursion, but never do that with variables, that change meanwhile.

    You can try it out yourself by playing with debug_zval_dump(), like this:

    <?php
    function rec_func_ref(&$x) {  
       //echo $x;
       if ($x < 100000) {
          $x++;
          rec_func_ref($x);
       }
      echo 'rec_func_ref:'.$x.'------<br />';
      debug_zval_dump($x);
      echo "<br />";
    }
    
    function rec_func_not_ref($x) {  
       //echo $x;
       if ($x < 100000) {
          $x++;
          rec_func_not_ref($x);
       }
      echo 'rec_func_not_ref:'.$x.'------<br />';
      debug_zval_dump($x);
      echo "<br />";
    }
    
    
    $a = 1;
    rec_func_ref($a);
    $a = 1;
    rec_func_not_ref($a);
    ?>
    
    评论

报告相同问题?

悬赏问题

  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了