查看释放的内存会导致访问冲突吗?

可以访问(只读)释放的内存会导致访问冲突,如果是,在什么情况下?

是的,它可以。 “访问冲突”(“分段错误”等)是当进程试图访问(甚至仅仅是为了读取)操作系统已知为“空”,“已释放”的内存时,OS /硬件通常生成的响应。由于其他原因无法访问。 这里的关键时刻是OS /硬件必须知道内存是空闲的。 C标准库的内存管理function不一定会将’free’d内存返回给OS。 他们可能(并将会)保留它以供将来分配。 所以在某些情况下,访问’free’d内存不会导致“访问冲突”,因为从操作系统/硬件的角度来看,这个内存还没有被真正释放。 但是,在某些时候,标准库可能会决定将收集的可用内存返回给操作系统,之后尝试访问该内存通常会导致“访问冲突”。

你问“可以”而不是“会”,所以你的回答是肯定的。 指向不属于您的程序的内存是未定义的行为,因此可能发生任何事情。

会吗? 要看。 这是特定于操作系统的。 你可能能够逃脱它,但显然你不能依赖它。 尝试取消引用它可能会导致exception,因为操作系统已经回收了内存以供自己使用。 (再次,OS特定)。

在Windows上: 在Win32中管理虚拟内存

免费,预留和承诺的虚拟内存

进程中的每个地址都可以被视为在任何给定时间的空闲,保留或提交。 进程从所有地址开始,这意味着它们可以自由地提交到内存或保留供将来使用。 在使用任何空闲地址之前,必须先将其分配为保留或已提交。 尝试访问保留或空闲的地址会生成 访问冲突exception

不会

从理论上讲,内存管理器可以向操作系统返回空间,但很少这样做。 并且在没有将空间一直返回到内核的情况下,MMU将永远不会涉及,因此无法进行故障。

问题是分裂 。 可变大小的块的分配是低效的,并且通用分配器不能移动分配的块,因为它们不知道什么指向什么,因此它们不能合并块,除非它们碰巧是相邻的。

测量结果表明,在稳态过程中,碎片开销往往约为50%,因此每隔一个块都不可触及,除非它们比块小得多,否则不可能返回页面,而它们通常不会。

此外,返回嵌入在堆中的页面的簿记挑战是令人生畏的,因此大多数内存管理器甚至都没有这种能力,即使在他们有机会的不太可能的情况下也是如此。

最后,传统的流程​​模型不是稀疏对象。 这种低级软件保守开发并且存在很长时间。 今天开发的分配器可能只是尝试稀疏分配,但大多数子系统只使用C库中已有的任何东西, 不是随便重写的明智之举。

它当然被允许; 如果“使用通过调用freerealloc函数解除分配的空间的指针的值”,C标准直截了当地表明行为是未定义的。 实际上,由于操作系统的工作方式,你更容易获得垃圾而不是崩溃,但很简单,你不能假设在调用未定义的行为时会发生什么。

释放的内存不再属于您,确切地说,相应的物理内存页面超出了您的进程地址空间,在您释放后可能已经重新映射到其他进程地址空间,并且您访问的地址尚未分配物理页面和做映射; 因此即使只读取也会发生“访问冲突”或“段错误”。 它通常由处理器硬件触发,例如GP#,而不是OS。

但是,如果拥有已释放内存的特定物理页面仍在您的任务上下文的控制之下,则说明您的进程仍然使用了部分页面,则可能不会发生“访问冲突”或“段错误”。

我们可以访问它但不鼓励。 例如

 void main() { char *str, *ptr; str = (char *)malloc(10); ptr = str; strcpy(str, "Hello"); printf("%s", str); free(str); printf("%s", ptr); } 

如果你问这个是因为你已经分析了你的代码并发现访问释放的内存会提供显着的性能提升,那么如果释放的块很小 ,那么答案很少 。 如果您想确定,请提供您自己的malloc()和free()的替代实现。