2

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

1.-假设我通过使用函数的无限迭代来运行具有递归解决方案的程序。理论上程序崩溃(堆栈溢出),但它会给计算机本身带来一些麻烦吗?(可能是 RAM 或 SO)。

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

3.- 得到分段错误(堆)的问题是什么。

欢迎与此相关的其他一些危险或关心。

4

4 回答 4

10

因此,每当使用堆栈存储时,都需要手动解除分配,但如果使用堆,则会自动完成解除分配。

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

当您从堆中分配时,分配的内存保持“正在使用”,直到它被释放。如果你不这样做,你的程序,如果它运行了足够长的时间并继续分配“东西”,将使用它所有可用的内存,并最终失败。

请注意,“stackfault”几乎不可能在应用程序中恢复,因为堆栈已满时不再可用,并且大多数“从错误中恢复”的操作将涉及使用一些堆栈内存。处理器通常有一个特殊的陷阱来从堆栈故障中恢复,但这会影响操作系统,如果操作系统确定应用程序已用完堆栈,它通常毫不留情 - 它只是立即“杀死”应用程序.

1.-假设我通过使用函数的无限迭代来运行具有递归解决方案的程序。理论上程序崩溃(堆栈溢出),但它会给计算机本身带来一些麻烦吗?(可能是 RAM 或 SO)。

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

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

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

一旦程序完成(并且大多数使用“太多内存”的程序确实会在某个时候以某种方式终止)。

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

但这些都是极端情况,大多数系统都设置成这样一个应用程序吞噬所有可用内存就会在系统的其余部分受到影响之前失败 - 并非总是如此,当然不能保证“导致”问题的应用程序是如果操作系统仅仅因为“消耗大量内存”而杀死应用程序,那么第一个被杀死的应用程序。Linux 确实有一个“内存不足杀手”,这是确保系统可以继续工作的一种非常激烈的方法[通过“工作”的某种定义]。

3.- 得到分段错误(堆)的问题是什么。

分段错误与堆没有直接关系。术语分段错误来自较旧的操作系统(Unix 风格),它们将内存的“段”用于不同的用途,而“分段错误”是指程序超出分配的段时。在现代系统中,内存被分成“页面”——通常每个 4KB,但一些处理器有更大的页面,并且许多现代处理器支持“大页面”,例如 2MB 或 1GB,用于大块内存.

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

于 2013-01-16T20:51:20.567 回答
6

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

其次,您提出的 3 个问题与 C++ 语言无关,而是仅针对您运行 C++ 程序的环境/操作系统来回答。现代操作系统通常会隔离进程,因此行为不端的进程不会t 践踏操作系统内存或其他正在运行的程序。例如,在 Linux 中,每个进程都有自己的地址空间,由内核分配。如果行为不端的进程试图写入其分配的地址空间之外的内存地址,操作系统将发送一个 SIGSEGV(分段错误),这通常会中止该进程。较旧的操作系统,如 MS-DOS,没有这种保护,因此写入无效指针或触发堆栈溢出可能会使整个操作系统崩溃。

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

于 2013-01-16T20:32:48.467 回答
0

1.- Let'suposse that I run a program with a recursion solution by using an infinite iteration of functions. Theoretically the program crashes (stack overflow), but does it cause some trouble to the computer itself? (To the RAM maybe or to the SO).

堆栈溢出不应给操作系统或计算机造成麻烦。任何现代操作系统都为每个进程提供了一个隔离的地址空间。当一个进程试图在其堆栈中分配比可用空间更多的数据时,操作系统会检测到它(通常通过异常)并终止该进程。这保证不会影响其他进程。

2.- What happens if I forget to dealocate memory on the heap. I mean, does it just cause trouble to the program or it is permanent to the computer in general. I mean it might be that such memory could not be used never again or something.

这取决于您的程序是否是一个长时间运行的进程,以及您未能释放的数据量。在长时间运行的进程(例如服务器)中,反复出现的内存泄漏可能会导致抖动:一段时间后,您的进程将使用大量内存,以至于无法放入您的物理内存。这本身不是问题,因为操作系统提供虚拟内存,但操作系统将花费更多时间将内存页面从物理内存移动到磁盘,而不是做有用的工作。这可能会影响其他进程,并且可能会显着降低系统速度(以至于重新启动它可能会更好)。

3.- What are the problems of getting a segmentation fault (the heap).

分段错误会使您的进程崩溃。它与堆的使用没有直接关系,而是与访问不属于您的进程的内存区域相关(因为它不是其地址空间的一部分,或者因为它是,但它已被释放)。根据您的进程在做什么,这可能会导致其他问题:例如,如果进程在崩溃发生时正在写入文件,那么它很可能最终会损坏。

于 2013-01-16T20:54:15.800 回答
0

首先,stack 表示自动内存,heap 表示手动内存。两者都有解决方法,但这通常是一个更高级的问题。

  1. 在现代操作系统上,您的应用程序会崩溃,但操作系统和机器作为一个整体将继续运行。这条规则当然有例外,但它们(再次)是一个更高级的话题。

  2. 从堆中分配然后在完成后不释放只是意味着即使您没有使用它,您的程序仍然被认为正在使用它。如果未选中,您的程序将无法分配内存(内存不足错误)。如何处理内存不足错误可能意味着从崩溃(未处理的错误导致未处理的异常或访问 NULL 指针并生成分段错误)到奇怪的行为(捕获异常或测试 NULL 指针但没有特殊处理情况下)一无所有(妥善处理)。

在现代操作系统上,当您的应用程序退出时,内存将被释放。

  1. 通常意义上的分段错误只会使您的应用程序崩溃。操作系统可能会立即关闭文件或套接字句柄。它还可以执行应用程序内存的转储,以便您可以尝试使用旨在执行此操作的工具在死后对其进行调试(更高级的主题)。

或者,大多数(我认为?)现代操作系统将使用一种特殊的方法来告诉程序它做了坏事。然后由程序的代码决定它是否可以从中恢复,或者是否可以为操作系统添加额外的调试信息,或者其他什么。

  1. 我建议您研究一下自动指针(也称为智能指针),以使您的堆表现得有点像堆栈——当您使用完它时会自动释放内存。如果您使用的是现代编译器,请参阅 std::unique_ptr。如果找不到该类型名称,请查看 boost 库 (google)。这是一个更高级但非常有价值的知识。

希望这可以帮助。

于 2013-01-16T20:55:50.477 回答