我们都知道函数执行时引擎会将函数指针压入执行栈,我的疑问是,该函数彻底执行完成之前,这个指针是一直保留在执行栈中吗? 比如有人说,写递归函数的时候,如果没有合适的跳出条件就会爆栈 我觉得内存是会爆,但是爆的不应该是栈。应该是,当函数任务被加入任务队列的时候,该函数指针就被删除了。
提示你是爆栈啊要不你哪知道你写错了,(我瞎猜的)
- 函数彻底执行完成之前,这个指针是一直保留在执行调用栈中
- 调用栈一般会额外限制一个一般来说远低于内存的大小限制,所以确实是爆栈
- 在尾递归优化方案中,外层函数帧可以被丢弃这样可以减少一些栈的消耗
@zy445566 之前我也是这么认为,但是看到下面两篇文章,都有说到,调用栈清空后才会去执行任务队列中的任务,这时我懵了 https://segmentfault.com/a/1190000016278115 https://zhuanlan.zhihu.com/p/55511602 (查阅时,页面内搜索“清空”,快速定位)
栈也是内存的一种,爆栈和爆内存不是一个说法吗。。递归也不一定跟消息队列有直接关系,队列放置的是异步任务。最普通的递归求阶乘,同步任务不设置结束条件也会栈溢出,这相当于是一个死循环。
@JarvisQJ 我先做个假设,如果都是同步代码,那么执行完了,调用栈本身就是空的,所以清空不清空都是一样的。
如果存在异步代码,假设执行完同步代码,调用栈还有数据?如果是,只能猜测是为了防止异步代码被提前调用,那么为什么会提前调用,什么时候会出现这种情况,我觉得可以看V8和nodejs的测试用例中应该有。但是如果不存在这种情况,那么本身清空有什么意义?只能看它代码实现为什么会影响执行结果。
所以就算没有保留也只是nodejs或V8做的一种特殊处理,所以我觉得依旧可以认为函数彻底执行完成之前,这个指针是一直保留在执行调用栈中。
当然如果有大牛可以直接解答清空调用栈的原因和什么情况是必须清空的,那肯定更好了。
谢谢大家的解惑。 这个问题产生根源是,本人对于同步任务和异步任务理解错误(误以为所有的函数都是异步的,从而认为所有任务都会加入任务队列,最终得出了矛盾)。 很惭愧,曾经很清楚理解的概念,多年后记忆混淆,搞出了状况。 异步任务的执行需要通过任务队列配合主线程完成执行,而同步任务直接由主线程压入执行栈执行。 异步任务包括ajax、事件、回调函数、promise等; 同步任务除了以上,包括普通函数、递归等