栈溢出怎么办(栈溢出的原因及解决办法)

寄存器是位于中央处理单元(CPU)内部的一小块高速处理器,用来存储和执行「指令、数据、中间计算结果」,每个 CPU 都有一组寄存器。
寄存器有极快的访问速度,远快于主内存,因此,CPU 可以更快对寄存器中数据进行操作,从而提高程序的执行效率。
什么是栈
在常见的程序里不同的寄存器扮演不同的角色,最特别的是栈指针用来标记运行时栈的结束位置。在 CPU 中有一个特殊的寄存器,叫做栈指针寄存器。
栈是一种数据结构,可以添加或者删除,遵循「后进先出」原则,通过 push 操作把数据压入栈中,通过 pop 操作删除数据,「删除的值永远是最近被压入而且仍然在栈中的值」。
栈可以实现为一个数组,总是从数组的一端插入和删除元素,这一端被称为栈顶。
栈地址
在栈中,数据是从高地址向低地址生长的,栈指针指向栈的顶部,每次压入一个值到栈中,都需要将栈指针向下移动来分配新的空间。栈是向下增长的,这样一来,栈顶元素的地址是所有栈中元素地址中最低的。
当我们需要将一个四字的值(一字等于两字节,四字等于八字节)压入栈时,会将栈指针向下移动 8个字节的位置。
具体来说,如果当前栈指针地址为 X,将栈指针减 8 后,栈指针的地址为 X-8 的位置,这个是新值存储的位置。
当我们弹出一个四字的操作的时候,会从栈顶位置读取数据,然后将栈指针加 8,恢复到上一个指针地址。
根据惯例,在画图的时候,我们的栈是倒过来画的,栈顶在图的底部。
CPU 栈溢出
在程序执行过程中,由于函数调用过深或者递归调用过深,导致 CPU 的栈空间指针一直减少,当栈指针减少到足够低的数值时,它会在地址空间回绕,从最大的值开始减少,当绕回到栈尾指针的时候,这种情况就会导致栈溢出,引发程序错误。
当用 C 语言编写一个函数时,然后递归调用自身,每次函数调用都会在栈上添加一个新的函数调用信息,当这个函数没有设置退出条件的时候,无限递归下去,就会消耗完所有的栈空间,引发栈溢出。
上面是 CPU 中栈指针寄存器的溢出,JavaScript 不是也栈溢出么?
我们在编写 JS 代码时,也会遇到栈溢出的问题。JavaScript 的栈溢出与 CPU 的栈寄存器的溢出在概念上是相似的,因为它们都涉及到了「栈」这种数组结构的使用,也都是因为栈空间不足引起的,只不过,他们发生在不同的层次。
JavaScript 栈溢出
JavaScript 的运行环境通常会提供一个抽象的执行环境,包括 JavaScript 引擎的调用栈,这个执行境是由运行环境管理的,不是由 CPU 直接管理的。
当引擎在执行代码的时候,会为每个函数创建一个执行上下文,并将它压入调用栈,这个上下文包含函数的参数、局部变量、返回地址等信息。当函数执行完后,其执行上下文会被弹出调用栈。
function foo() {    foo();}foo();
相同的,如果函数的调用过深或者递归调用过深,没有正确的退出条件,超过了引擎的最大的调用深度,同样会发生栈溢出。
区别是什么
CPU 的栈寄存器溢出发生在硬件级别的 CPU 中,当溢出会导致程序崩溃、数据丢失、安全漏洞等问题。
对于 JavaScript 来说,虽然运行环境对调用栈有一定的保护和限制,但也会导致程序崩溃或冻结,当发生栈溢出的时候,引擎会抛出一个错误,然后停止执行 JavaScript 代码,这个过程是在引擎的管理下进行的,相对于 CPU 的栈溢出,JavaScript 栈溢出不会影响到 CPU 的硬件栈。
无论是 CPU 的栈溢出还是 JavaScript 的栈溢出,都需要开发者进行适当的代码设计和测试,以避免发生这些问题,并确保程序的稳定性和安全性。

题图生成:Pixabay – EliFrancis
内容优化:ChatGPT

原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34614.html

(0)
小道研究's avatar小道研究
上一篇 2024年4月19日 下午8:33
下一篇 2024年4月19日 下午8:35

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注