我试图理解对象(变量,函数,结构等)如何在c ++中工作。在这种情况下,我看到基本上有两种存储方式:堆栈和堆。因此,无论何时使用堆存储,都需要手动处理,但如果使用堆栈,则自动完成交易。所以我的问题与不良实践可能导致程序本身或计算机的各种问题有关。例如:
1.-让我们通过使用无限迭代的函数来运行带递归解的程序。从理论上讲,程序崩溃(堆栈溢出),但这会给计算机本身带来一些麻烦吗? (可能是对RAM或对SO)。
2.-如果我忘记在堆上处理内存会发生什么。我的意思是,它只会给程序带来麻烦,或者它对计算机来说是永久性的。我的意思是,这样的记忆可能永远不会再被使用。
3.-获得分段错误(堆)有什么问题。
欢迎与此相关的其他一些危险或关注。
答案 0 :(得分:9)
因此,无论何时使用堆栈存储,都需要 手动处理,但如果使用堆,那么交易就是 自动完成。
当您在函数中使用堆栈 - 局部变量时 - 它们在函数结束(返回)时自动释放。
从堆中分配时,分配的内存将保持“正在使用中”,直到它被释放。如果你不这样做,你的程序,如果它足够长并且继续分配“东西”,将使用它可用的所有内存,并最终失败。
请注意,“stackfault”几乎不可能从应用程序中恢复,因为堆栈在它已满时不再可用,并且大多数“从错误中恢复”的操作将涉及使用SOME堆栈内存。处理器通常有一个特殊的陷阱来从堆栈故障中恢复,但这会使操作系统失效,如果操作系统确定应用程序已经用尽堆栈,它通常根本不显示任何怜悯 - 它只会立即“杀死”应用程序。
1.-让我们通过使用无限迭代的函数来运行带递归解的程序。从理论上讲,该计划 崩溃(堆栈溢出),但它会导致一些麻烦 电脑本身? (可能是对RAM或对SO)。
不,计算机本身并没有因此受到伤害。如果你的程序没有保存用户正在处理的东西,那么当然可能会有数据丢失。
除非硬件设计非常糟糕,否则编写会对计算机造成任何损害的代码非常困难,除了丢失存储的数据(当然,如果你编写一个程序将整个硬盘从第一个硬盘填满到最后一个扇区,您的数据将被您的程序填充磁盘所覆盖 - 这可能导致机器在磁盘上重新安装操作系统之前无法再次启动。但RAM和处理器不会因编码错误而受损(幸运的是,大多数程序员一次又一次地犯错误)。
2.-如果我忘记在堆上处理内存会发生什么。我的意思是,它只会给程序带来麻烦,还是永久性的 电脑一般。我的意思是这样的记忆可能不是 再也没用过。
程序完成后(大多数使用“太多内存”的程序会以某种方式终止,在某些时候)。
当然,操作系统和其他应用程序处理“根本没有可用内存”的程度有所不同。操作系统本身通常都可以,但是一些写得不好的驱动程序可能会崩溃,因此如果你运气不好会导致系统重启。由于没有足够的内存,应用程序更容易崩溃,因为当没有可用内存时,分配最终为NULL(零)作为“返回地址”。在现代操作系统中使用地址零几乎总会导致“分段错误”或类似问题(有关详细信息,请参见下文)。
但是这些都是极端情况,大多数系统的设置使得一个应用程序吞噬所有可用内存本身会在系统其余部分受到影响之前失败 - 并非总是如此,并且肯定无法保证应用程序“导致”如果操作系统因为“吃掉大量内存”而杀死应用程序,那么问题就是第一个被杀死的问题。 Linux确实有一个“内存不足”,这是一种非常激烈的方法,可以确保系统能够继续工作[通过某种“工作”定义]。
3.-获得分段错误(堆)有什么问题。
分段错误不直接与堆有关。术语分段错误来自较旧的操作系统(Unix风格),它使用内存的“段”用于不同的用法,而“分段错误”是指程序超出它的分配段。在现代系统中,内存被分成“页面” - 每个通常为4KB,但是一些处理器具有更大的页面,并且许多现代处理器支持“大页面”,例如2MB或1GB,用于大块内存。
现在,如果您使用的地址指向不存在的页面(或不是“您的”),则会出现分段错误。这通常会在那时和那里结束应用程序。您可以“捕获”分段故障,但在我所知道的所有操作系统中,尝试继续使用此“陷阱”无效 - 但您可以存储一些文件以解释发生的情况并帮助解决问题以后等等。
答案 1 :(得分:6)
首先,您对堆栈/堆分配的理解是倒退的:堆栈分配的数据在超出范围时会自动回收。动态分配的数据(使用new
或malloc
分配的数据)(通常是堆分配的数据)必须使用delete
/ free
手动回收。但是,您可以使用C ++析构函数(RAII)自动回收动态分配的资源。
其次,你提出的3个问题与C ++语言无关,而是它们只对你运行C ++程序的环境/操作系统负责。现代操作系统通常将进程隔离,从而导致行为不端进程不会践踏操作系统内存或其他正在运行的程序。例如,在Linux中,每个进程都有自己的地址空间,由内核分配。如果行为不当的进程尝试写入其分配的地址空间之外的内存地址,操作系统将发送SIGSEGV(分段错误),通常会中止该进程。较旧的操作系统(如MS-DOS)没有这种保护,因此写入无效指针或触发堆栈溢出可能会导致整个操作系统崩溃。
同样,对于大多数主流的现代操作系统(Linux / UNIX / Windows等),内存泄漏(动态分配但从未回收的数据)仅影响分配它们的进程。当进程终止时,操作系统将回收进程分配的所有内存。但同样,这是操作系统的一个特性,与C ++语言无关。可能有一些较旧的操作系统,即使是操作系统也不会回收泄漏的内存。
答案 2 :(得分: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.
这取决于您的程序是否是一个长时间运行的进程,以及您无法解除分配的数据量。在长时间运行的进程(例如服务器)中,经常性内存泄漏可能导致thrashing:一段时间后,您的进程将使用如此多的内存,以至于它不适合您的物理内存。这本身不是问题,因为操作系统提供virtual memory,但操作系统将花费更多时间将内存页面从物理内存移动到磁盘而不是执行有用的工作。这可能会影响其他进程,并且可能会显着降低系统速度(重新启动它可能会更好)。
3.- What are the problems of getting a segmentation fault (the heap).
分段错误会导致您的进程崩溃。它与堆的使用没有直接关系,而是与访问不属于您的进程的内存区域有关(因为它不是其地址空间的一部分,或者因为它是,但它已被释放)。根据您的进程正在执行的操作,这可能会导致其他问题:例如,如果进程在发生崩溃时写入文件,则很可能最终会损坏。
答案 3 :(得分:0)
首先,堆栈表示自动内存,堆表示手动内存。有两种方法,但这通常是一个更高级的问题。
在现代操作系统上,您的应用程序将崩溃,但操作系统和整个机器将继续运行。这条规则当然有例外,但它们(再次)是一个更高级的主题。
从堆中分配,然后在完成后不释放,这意味着即使您没有使用它,您的程序仍然被认为正在使用内存。如果未选中,程序将无法分配内存(内存不足错误)。如何处理内存不足错误可能意味着崩溃(未处理的错误导致未处理的异常或访问的NULL指针并生成分段错误)到奇怪的行为(捕获异常或测试NULL指针但没有特殊处理) (无论如何)(处理得当)。
在现代操作系统上,当您的应用程序退出时,内存将被释放。
或者,大多数(我认为?)现代操作系统将使用一种特殊方法告诉程序它已经做了一些坏事。然后由程序的代码决定它是否可以从中恢复,或者可能为操作系统添加额外的调试信息,或者真正的其他调试信息。
希望这有帮助。