js递归函数造成的内存泄露(堆栈溢出)问题的解决方法

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。

更多精彩内容请看 web前端中文站
www.lisa33xiaoq.net 可按Ctrl + D 进行收藏

对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。

不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。

js递归函数造成的内存溢出(堆栈溢出)问题的解决方法

关于堆栈的溢出问题,在 Javascript 日常开发中很常见,网上关于这类问题还是比较多的。本文旨在描述如何解决此类问题。

首先看一个实例(当然你可以使用更容易的方式实现,这里我们仅探讨递归):

 function isEven (num) {     
 if (num === 0) {         
 return true;     }  
 //web前端中文站:www.lisa33xiaoq.net     
 if (num === 1) {         
 return false;     }  
 //www.lisa33xiaoq.net    
 return isEven(Math.abs(num) - 2); } 
 //Outputs: 
 true console.log(isEven(10)); 
 //Outputs: 
 false console.log(isEven(9));

上面的程序,看起来没有任何问题,运行几次也看不出来有什么问题。然而当我们让上面的参数改为 10000 的时候,会发现有内存泄漏(堆栈溢出)问题。

 //不同的javascript引擎报错可能不同 
 //Outputs: 
 Uncaught RangeError: Maximum call stack size exceeded  
 console.log(isEven(10000));

原因是每次执行代码时,都会分配一定尺寸的栈空间(Windows系统中为1M),每次方法调用时都会在栈里储存一定信息(如参数、局部变量、返回值等等),这些信息再少也会占用一定空间,成千上万个此类空间累积起来,自然就超过线程的栈空间了。那么如何解决此类问题?

使用闭包

 function isEven (num) {     
 if (num === 0) {         
 return true;     }     
 if (num === 1) {         
 return false;     }  
 //web前端中文站lisa33xiaoq.net  
 return function() {         
 return isEven(Math.abs(num) - 2);     } } 
 //Outputs: true console.log(isEven(4)()());

此时每次调用时,返回一个匿名函数,匿名函数执行相关的参数和局部变量将会释放,不会额外增加堆栈大小。

优化调用

上例调用比较麻烦,优化如下:

 function isEven (num) {     
 if (num === 0) {         
 return true;     }     
 if (num === 1) {          
 return false;     }     
 return function() {         
 return isEven(Math.abs(num) - 2);     } } 
 function trampoline (func, arg) {     
 var value = func(arg);     
 while(typeof value === "function") {         
 value = value();     }     
 return value; } 
 //Outputs: true 
 console.log(trampoline(isEven, 10000)); 
 //web前端中文站www.lisa33xiaoq.net
 //Outputs: false console.log(trampoline(isEven, 10001));

通过上面的两种办法,都可以解决这类js递归函数造成的内存泄漏(堆栈溢出)问题。

【注:本文源自网络文章资源,由站长整理发布】

0
如无特殊说明,文章均为原作者原创,转载请注明出处

该文章由 发布

这货来去如风,什么鬼都没留下!!!
发表我的评论

Hi,请填写昵称和邮箱!

取消评论
代码 贴图 加粗 链接 删除线 签到