为什么我可以信任内存分配?

时间:2017-03-19 07:51:20

标签: c memory memory-management malloc free

我目前正在学习使用C语言的CS课程。我的教科书似乎暗示指针变量仍保留先前分配给它的内存的地址,即使在调用free()之后也是如此 - 假设我之前使用过malloc()。这是否意味着记忆的某些部分会被锁定"当调用malloc()时,我的指针数据保持不变?什么阻止其他进程 - 比如谷歌浏览器或某些应用程序 - 搞乱我的变量?我可以轻松地在无效索引处为数组赋值,从而导致事情中断。我也可以不正确地访问内存,再次使用无效索引的数组,给我垃圾,或者,如果我真的很幸运,给我一个有意义的值。什么阻止计算机陷入混乱!

5 个答案:

答案 0 :(得分:6)

  

指针变量仍然保存先前分配给它的内存的地址,即使在调用free()后也是如此

这是事实。这种情况被称为"悬空指针"。你的程序不允许使用这些指针;否则,其行为未定义。

  

这是否意味着记忆的某些部分会被锁定"当调用malloc()时,我的指针数据保持不变?

它们仅在malloc不会再次为您的程序返回分配范围的意义上被锁定,直到您free它为止。但是没有内置保护:如果你的程序意外地写入一个释放的指针,它可能会覆盖合法变量中的数据,导致在没有proper tools的情况下很难捕获的错误。

  

什么阻止其他进程 - 比如谷歌浏览器或某些应用程序 - 搞乱我的变量?

其他应用程序在不同的内存空间中运行。硬件和操作系统可确保其他进程被锁定在程序的内存空间中。

答案 1 :(得分:4)

  

什么阻止计算机陷入混乱!

现代处理器的操作模式称为带有虚拟内存的保护模式 - 正常程序(进程)在所谓的用户模式下运行,并且看到的内存空间与其他当前正在运行的进程不同。然后,操作系统确保所有这些不当行为都包含在一个这样的过程中 - 虽然这种访问可能会导致崩溃,但它只会被包含在这一个过程中。

在旧版本的Windows中并非如此 - 虽然Windows 3可以使用x86保护模式,但它在相同的权限级别下运行所有​​程序 - 可怕的蓝屏死机可能会占用整个系统:

BSOD

至于那部分

  

我的教科书似乎暗示指针变量仍保留先前分配给它的内存的地址,即使在调用free()之后 - 假设我之前使用过malloc()。

这实际上并非严格属实。 C标准明确指出在指针上调用free之后,指针本身的值变为不确定。它可能仍然指向您的实施中的相同地址,但所有赌注都已关闭。以下程序甚至可能在某个平台上崩溃:

void *ptr = malloc(42);
free(ptr);

// some other code that is between here...

if (ptr) {
    ...
}

正如C标准所说6.2.4p2

  

当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。

Appendix J.2. Undefined behavior

  

使用指向生命周期结束的对象的指针的值(6.2.4)。

编译器可能会导致一种可能的行为知道在free之后不需要该值。因此,如果上述代码中的ptr存储在 register ,编译器可以自由地覆盖那里之间的某些代码的值,随后变量ptr可能表现为它在{{1}中使用时的未初始化值}}

使用值不确定的指针将导致各种有趣的行为,例如由this question here证明。编译器不需要产生你期望的值,它只需要符合标准。

在任何情况下,本书都是正确的,因为在您为if设置新值之前不要使用ptr,这只是具体的例子。这本书具有误导性,因为它只是众多可能结果中的一种,正如C中未定义的行为所常见的那样。

答案 2 :(得分:4)

早在20世纪70年代,就有不止一个人使用的计算机。当其中一个人撞毁系统时,其他用户讨厌它。所以他们发明了虚拟机。不像你现在听到的那样,或者好吧,是的。是的。

虚拟内存,以便程序可以同时使用地址0x4000000。虚拟CPU,以便许多程序可以在一个CPU上运行时间切片。虚拟输入和输出设备。

所有这些都是50年前在Multics,VMS,Unix,IBM OS / 360等发明的。

答案 3 :(得分:1)

  

什么阻止其他进程 - 比如谷歌浏览器或某些应用程序 - 搞乱我的变量?

所有现代桌面/服务器操作系统都确保任何其他程序都无法访问一个程序的内存空间。这主要来自CPU中内存管理单元的配置(由OS管理)。

然而,并非所有操作系统都这样做。 DOS没有,主要是因为它是作为一个单一的过程操作系统; TSR程序可以访问整个机器中的任何内容,包括前台程序。

某些实时操作系统(如VxWorks(特别是旧版本))是多任务处理,抢占式操作系统,但不提供任何进程间内存分离。设计人员选择这样做是为了减少上下文切换时间,这在实时操作系统中很方便。

答案 4 :(得分:1)

这是思考它的一种方式。让我们把计算机内存分成"页面"。让我们想象每个"页面"是一张真正的纸张,我们用铅笔写数字。让我们想象一下,我们程序使用的所有页面都存储在文件柜中,从第0页到第N页。让我们想象一下,我们有一些简单的方法来跟踪文件中的哪些页面内阁正在使用 - 也许我们折叠在顶角或其他东西。最后,让我们想象一下纸张有点珍贵:我们从来没有把它丢掉。当我们需要一些新内存时,找到一个尚未使用的现有页面并删除它上面的任何内容是值得的,并再次使用它。

考虑到这个比喻,我们可以回答你的问题。

  

我的教科书似乎暗示指针变量仍保留先前分配给它的内存的地址。

右。当我们免费"一页内存,我们只是折叠上角(或其他)。但是我们还没有删除页面,因为没有必要(这将是低效的)。我们等到其他人稍后再分配页面以擦除它并在其上写下新的数字。

  

什么阻止其他进程 - 比如谷歌浏览器或某些应用程序 - 搞乱我的变量?

根据我迄今为止开发的类比,没有任何内容。事实上,如果你的计算机上的所有程序都直接访问了内存,就没有什么能阻止它们互相干扰内存,而且很糟糕。这就是为什么大多数计算机实际上并没有完成任务以便普通程序直接访问内存的原因。

相反,现在几乎所有通用计算机都包含内存管理单元(通常实现虚拟内存)。结果是每个程序都有自己的文件柜。一个程序可以搞乱其文件柜中的所有页面,它可以正确或错误地使用它们并且如果它真的想要混淆自己并崩溃,但是程序根本无法做任何事情将页面放在任何其他程序的文件柜中。它甚至不能偷看它们,更不用说写给它们了。