本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云
程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。
对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
关于堆栈的溢出问题,在 Javascript 日常开发中很常见,网上关于这类问题还是比较多的。本文旨在描述如何解决此类问题。
首先看一个实例(当然你可以使用更容易的方式实现,这里我们仅探讨递归):
function isEven (num) { if (num === 0) { return true; } //业余草:www.xttblog.com if (num === 1) { return false; } //业余草:www.xttblog.com 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; } //业余草:www.xttblog.com 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)); //业余草:www.xttblog.com //Outputs: false console.log(trampoline(isEven, 10001));
通过上面的两种办法,都可以解决这类js递归函数造成的内存泄漏(堆栈溢出)问题。
最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » js递归函数造成的内存溢出(堆栈溢出)问题的解决方法