可以访问(只读)释放的内存是否会导致访问冲突,如果是,在什么情况下?
答案 0 :(得分:9)
是的,它可以。 “访问冲突”(“分段错误”等)是当进程尝试访问(甚至只是为了读取)操作系统已知为“空”,“释放”或“已释放”的内存时,OS /硬件通常生成的响应因其他原因无法进入。这里的关键时刻是OS /硬件必须知道内存是空闲的。 C标准库的内存管理功能不一定会将'free'd内存返回给OS。他们可能(并将会)保留它以供将来分配。因此,在某些情况下,访问'free'd内存不会导致“访问冲突”,因为从操作系统/硬件的角度来看,这个内存还没有被真正释放。但是,在某些时候,标准库可能会决定将收集的可用内存返回给操作系统,之后尝试访问该内存通常会导致“访问冲突”。
答案 1 :(得分:7)
你问“可以”而不是“会”,所以你的回答是肯定的。指向不属于您的程序的内存是未定义的行为,因此可能发生任何事情。
是的吗?要看。这是特定于操作系统的。你可能能够逃脱它,但显然你不能依赖它。尝试取消引用它可能会导致异常,因为操作系统已经回收了内存以供自己使用。 (再次,OS特定)。答案 2 :(得分:3)
在Windows上:Managing Virtual Memory in Win32
免费,预留和承诺的虚拟内存
流程中的每个地址都可以 被认为是自由的,保留的, 或在任何特定时间承诺。一个 流程从所有地址开始 免费,意味着他们可以自由 致力于记忆或保留 未来的使用。在任何免费地址之前 必须首先使用它 分配为保留或已提交。 尝试访问保留或免费的地址会生成 访问冲突异常。
答案 3 :(得分:2)
理论上,内存管理器可以向操作系统返回空间,但很少这样做。并且没有将空间一直返回到内核,MMU将永远不会涉及,因此无法进行故障。
问题是碎片。可变大小的块的分配是低效的,并且通用分配器不能移动分配的块,因为它们不知道什么指向什么,因此它们不能合并块,除非它们碰巧是相邻的。
测量结果表明,在稳态过程中碎片开销往往约为50%,所以每隔一个块都不可触及,除非它们比块小得多,否则不可能返回页面,而且它们通常不是。
此外,返回嵌入在堆中的页面的簿记挑战是令人生畏的,因此大多数内存管理员甚至没有这种能力,即使在不太可能的情况下他们也有机会。
最后,传统的流程模型不是稀疏对象。这种低级软件保守开发并且存在很长时间。今天开发的分配器可能只是尝试稀疏分配,但大多数子系统只使用C库中已有的任何东西,并且 不是随便重写的明智之处。
答案 4 :(得分:1)
当然允许;如果使用“引用通过调用free
或realloc
函数解除分配的空间的指针的值”,C标准直截了当地说明行为未定义“。实际上,由于操作系统的工作方式,你更容易得到垃圾,而不是崩溃,但很简单,当你调用未定义的行为时,不允许假设。 / p>
答案 5 :(得分:1)
释放的内存不再属于您了,确切地说,相应的物理内存页不在您的进程地址空间之外,可能在您释放后已经重新映射到其他进程地址空间,并且您访问的地址尚未分配物理页面并进行映射;因此即使仅供阅读,也会发生“访问冲突”或“段错误”。它通常由处理器硬件触发,例如, GP#,而不是OS。
但是,如果拥有已释放内存的特定物理页面仍在您的任务上下文的控制之下,请说您的进程仍然使用了部分页面,则可能不会发生“访问冲突”或“段错误”。
答案 6 :(得分:0)
我们可以访问它但不鼓励。例如
void main()
{
char *str, *ptr;
str = (char *)malloc(10);
ptr = str;
strcpy(str, "Hello");
printf("%s", str);
free(str);
printf("%s", ptr);
}
答案 7 :(得分:-1)
如果你问这个是因为你已经分析了你的代码并发现访问释放的内存会提供显着的性能提升,那么如果释放的块很小,答案很少。如果您想确定,请提供您自己的malloc()和free()的替代实现。