C++中堆栈溢出和分段错误的危险

Dan*_*iaz 2 c++ stack-overflow segmentation-fault

我试图理解对象(变量,函数,结构等)如何在c ++中工作.在这种情况下,我看到基本上有两种存储方式:堆栈和堆.因此,无论何时使用堆存储,都需要手动处理,但如果使用堆栈,则自动完成交易.所以我的问题与不良实践可能导致程序本身或计算机的各种问题有关.例如:

1.-让我们通过使用无限迭代的函数来运行带递归解的程序.从理论上讲,程序崩溃(堆栈溢出),但这会给计算机本身带来一些麻烦吗?(可能是对RAM或对SO).

2.-如果我忘记在堆上处理内存会发生什么.我的意思是,它只会给程序带来麻烦,或者它对计算机来说是永久性的.我的意思是,这样的记忆可能永远不会再被使用.

3.-获得分段错误(堆)有什么问题.

其他一些与此相关的危险或关注是受欢迎的.

Mat*_*son 9

因此,无论何时使用堆栈存储,都需要手动处理,但如果使用堆,则自动完成交易.

当您在函数中使用堆栈 - 局部变量时 - 它们在函数结束(返回)时自动释放.

从堆中分配时,分配的内存将保持"正在使用中",直到它被释放.如果你不这样做,你的程序,如果它足够长并且继续分配"东西",将使用它可用的所有内存,并最终失败.

请注意,"stackfault"几乎是不可能的从应用程序的恢复,因为堆栈不再可用时,它的全部,大部分操作"从错误中恢复"将涉及使用一些堆栈存储器.处理器通常有一个特殊的陷阱来从堆栈故障中恢复,但是这会使操作系统失效,如果操作系统确定应用程序已经用尽堆栈,它通常根本不显示任何怜悯 - 它只会立即"杀死"应用程序.

1.-让我们通过使用无限迭代的函数来运行带递归解的程序.从理论上讲,程序崩溃(堆栈溢出),但这会给计算机本身带来一些麻烦吗?(可能是对RAM或对SO).

不,计算机本身并没有因此而受到伤害.如果您的程序没有保存用户正在处理的内容,那么当然可能会有数据丢失.

除非硬件是非常糟糕的设计,这是非常难写,导致的任何损害到计算机,超越丢失存储的数据(当然,如果你写,填补从第一个整个硬盘的最后一个扇区的程序代码,无论您的程序填充磁盘,您的数据都将被覆盖 - 这可能会导致计算机在磁盘上重新安装操作系统之前无法再次启动.但RAM和处理器不会因编码错误而受损(幸运的是,大多数程序员不时会犯错误).

2.-如果我忘记在堆上处理内存会发生什么.我的意思是,它只会给程序带来麻烦,或者它对计算机来说是永久性的.我的意思是,这样的记忆可能永远不会再被使用.

一旦程序结束(并且大多数使用"太多内存"的程序在某种程度上以某种方式终止).

当然,操作系统和其他应用程序处理"根本没有可用内存"的程度有所不同.操作系统本身通常都可以,但是一些写得不好的驱动程序可能会崩溃,因此如果你运气不好会导致系统重启.由于没有足够的内存,应用程序更容易崩溃,因为当没有可用内存时,分配最终为NULL(零)作为"返回地址".在现代操作系统中使用地址零几乎总会导致"分段错误"或类似问题(有关详细信息,请参见下文).

但这些都是极端的情况下,大多数系统都建立这样一个应用吞噬所有可用内存的系统的其余部分受到影响之前将自身失败 - 不总是这样,它肯定不能保证应用程序"造成"的问题是如果操作系统因为"吃掉大量内存"而杀死应用程序,那么第一个被杀死.Linux确实有一个"内存不足",这是一种非常激烈的方法,可以确保系统能够继续工作[通过某种"工作"定义].

3.-获得分段错误(堆)有什么问题.

分段错误不直接与堆有关.术语分段故障来自于所使用的内存的不同用途"段",以及"段错误"是老的操作系统(Unix风格)当程序走到外面它分配的段.在现代系统中,内存被分成"页" - 通常是4KB每一个,但是一些处理器有较大的网页,和许多现代处理器支持的"大页",为examble,2MB或1GB,它用于大块内存.

现在,如果您使用的地址指向不存在的页面(或不是"您的"),则会出现分段错误.这通常会在那时和那里结束应用程序.您可以"捕获"分段故障,但在我所知道的所有操作系统中,尝试继续使用此"陷阱"无效 - 但您可以存储一些文件以解释发生的情况并帮助解决问题以后等


Cha*_*via 6

首先,您对堆栈/堆分配的理解是倒退的:堆栈分配的数据在超出范围时会自动回收.动态分配的数据(用new或分配的数据malloc)通常是堆分配的数据,必须用delete/ 手动回收free.但是,您可以使用C++析构函数(RAII)自动回收动态分配的资源.

其次,你提出的3个问题与C++语言无关,而是它们只对你运行C++程序的环境/操作系统负责.现代操作系统通常将进程隔离,以便行为不当的过程不会t践踏OS内存或其他正在运行的程序.例如,在Linux中,每个进程都有自己的地址空间,由内核分配.如果行为不当的进程尝试写入其分配的地址空间之外的内存地址,操作系统将发送SIGSEGV(分段错误),通常会中止该进程.较旧的操作系统(如MS-DOS)没有此保护,因此写入无效指针或触发堆栈溢出可能会导致整个操作系统崩溃.

同样,对于大多数主流的现代操作系统(Linux/UNIX/Windows等),内存泄漏(动态分配但从未回收的数据)仅影响分配它们的进程.当进程终止时,操作系统将回收进程分配的所有内存.但同样,这是操作系统的一个特性,与C++语言无关.可能有一些较旧的操作系统,即使是操作系统也不会回收泄漏的内存.