【问题标题】:Garbage values in a multiprocess operating system多处理器操作系统中的垃圾值
【发布时间】:2012-08-19 21:05:22
【问题描述】:

自操作系统会话开始以来分配的内存是否保存垃圾值?在我们将其命名为程序运行时会话中的垃圾值之前,它是否具有某种意义?如果是,那为什么?

我需要一些有关 linux 内核编程、设备驱动程序编程的学习材料的建议,并且还想了解计算机设备的实际工作原理。我陷入了诸如“垃圾价值”之类的情况,并且觉得我还必须学习其他东西才能更好地理解编程语言。我正在自学,遇到很多令人困惑的情况。任何建议都会非常有帮助。

【问题讨论】:

  • 我怀疑这与垃圾收集有关。
  • 关于您问题中的“垃圾价值”一词指的是什么,您可以向我们推荐任何来源?因为通常,这只是指“恰好在内存中的某个随机值”(例如,因为我们还没有初始化那个地方)
  • C 语言,当变量只被定义和打印出来时。我只需要关于为什么会发生这种情况的信息。

标签: c linux memory-management kernel


【解决方案1】:

垃圾值,例如在 C 中,通常指的是如果您只是保留内存但从不初始化它,它将保存随机值,因为它还没有初始化(C 不会自动为您执行此操作;这只是开销,和 C 的设计是为了尽可能少的开销)。 内存中的随机值是之前存在的剩余值。

这些先前的值保留在那里,因为通常将内存设置为零 - 或任何其他值 - 没有太多用处 - 稍后将再次被覆盖。因为对于一般情况,读取未初始化的内存是没有用的(除非您想利用可能的安全问题 - 请参阅内存实际归零的特殊情况:Kernel zeroes memory?)。

【讨论】:

  • 谢谢,这真的很有帮助。
  • 只是一点提示:每个答案的左侧都有一个“向上”箭头和一个“接受”按钮,您可以通过它表示赞赏:D - 请注意,您只能接受一个答案!
  • 大声笑我知道@nyarlathotep,我需要一些声誉点才能做到这一点,这就是为什么我用文字来感谢我得到的帮助:D
【解决方案2】:

“垃圾价值”是一个俚语,意思是“我不知道那里有什么价值,或者为什么,因此我不会使用这个价值”。它是“无用的废话”意义上的“垃圾”,有时也是“别人的剩菜”意义上的“垃圾”。

形式上,C 中未初始化的内存采用“不确定值”。这可能是由 C 实现写在那里的一些特殊值,或者它可能是同一内存的早期用户“遗留”的东西。举个例子:

  • C 运行时的调试版本可能会用一个引人注目的值填充新分配的内存,因此,如果您在调试器中看到它时您期望自己存储的数据,您可以合理地得出结论,要么您忘记了初始化它,否则你找错地方了。
  • “正确”操作系统的内核在首次分配给进程时会覆盖内存,以避免一个进程看到“属于”另一个进程的数据,并且出于安全原因,这些数据不应跨进程边界泄漏。通常它会用一些已知值覆盖它,比如 0。
  • 如果你malloc内存,在里面写点东西,然后free它和malloc一些更多的内存,你可能会再次获得相同的内存,它之前的内容基本上完好无损。但从形式上讲,您新分配的缓冲区仍然是“未初始化的”,即使它恰好与您释放它时的内容相同,因为形式上它是一个全新的字符数组,恰好与旧的具有相同的地址。

在 C 中不使用“不确定值”的一个原因是标准允许它成为“陷阱表示”。当您将某些类型的某些不可能的值加载到寄存器中时,有些机器会注意到,并且您会遇到硬件故障。因此,如果内存以前用于,例如,int,但该值被读取为float,也就是说,剩余的位模式是否代表所谓的“信号 NaN”,即会停止程序吗?如果您将值作为指针读取并且它与类型不对齐,也会发生同样的情况。甚至整数类型也允许具有“奇偶校验位”,这意味着将垃圾值读取为int 可能具有未定义的行为。在实践中,我认为实际上没有任何实现确实具有int 的陷阱表示,并且我怀疑如果您只是读取指针值,任何实现都会检查未对齐的指针——尽管如果您取消引用它可能会。但是 C 程序员如果不谨慎,就什么都不是。

【讨论】:

    【解决方案3】:

    什么是垃圾值?

    当您在内存位置遇到值并且无法确定这些值应该是什么时,那么这些值对您来说就是垃圾值。即:值为不确定
    最常见的情况是,当您使用变量但未对其进行初始化时,该变量具有 Indeterminate 值并被称为具有垃圾值。请注意,使用未初始化变量会导致未定义行为,这意味着该程序不是有效的 C/C++ 程序,它可能会显示(字面上)任何行为。

    为什么特定值存在于该位置?

    当今的大多数操作系统都使用 virtual memory 的概念。用户程序看到的内存地址是虚拟内存地址而不是物理地址。虚拟内存的实现将虚拟地址空间划分为页面,即连续的虚拟内存地址块。一旦使用完毕,这些页面通常至少有 4 KB。这些页面没有明确擦除其内容,它们仅被标记为可重复使用,因此如果未正确初始化,它们仍包含旧内容。

    【讨论】:

      【解决方案4】:

      如果你声明一个变量而不将它初始化为一个特定的值,它可能包含一个先前由另一个程序分配的值,该程序已经释放了那块内存,或者它可能只是一个随机值,来自计算机已启动(iirc,PC 过去在启动时将所有 RAM 初始化为 0,因为早期版本的 DOS 需要它,但新计算机不再这样做)。例如,您不能假设该值为零。

      【讨论】:

        【解决方案5】:

        在典型的操作系统上,您的用户空间应用程序只能看到一系列虚拟内存。由内核将此虚拟内存映射到实际的物理内存。

        当一个进程请求一块(虚拟)内存时,它最初会保留其中的任何内容——它可能是进程的另一部分之前使用的重用内存,也可能是一个完全不同的进程一直在使用......或者它可能根本没有被触及,并且处于您打开机器电源时的任何状态。

        通常没有人会代表您用零(或任何其他同样任意的值)擦除内存页面,因为没有意义。完全取决于您的应用程序以任何您喜欢的方式使用内存,如果您仍然要写入它,那么您不必关心它之前的内容。

        因此,在 C 中,由于未定义行为的痛苦,根本不允许在写入变量之前读取变量。

        【讨论】:

        • "通常没有人去用零擦除内存页" => 并非总是如此 stackoverflow.com/questions/6004816/kernel-zeroes-memory
        • @nyarlathotep:谢谢,非常有趣!这确实是系统级别的“不为不使用的东西付费”效率和安全问题之间的权衡。
        • 通常这不是一个很大的效率成本,因为它只需要在页面映射时发生,这本身有点慢。如果清除被认为是昂贵的,那么当机器处于空闲状态时,操作系统可以在未分配的页面上作为低优先级的后台任务工作,尽管我不知道 Linux 是否真的这样做。对于某些类型的内存(闪存),清除连续范围的块非常便宜。
        猜你喜欢
        • 2014-12-07
        • 2020-04-28
        • 1970-01-01
        • 2022-06-14
        • 2023-03-16
        • 1970-01-01
        • 2015-07-21
        • 2012-04-06
        • 2017-01-25
        相关资源
        最近更新 更多