【问题标题】:Why does Malloc() care about boundary alignments?为什么 Malloc() 关心边界对齐?
【发布时间】:2014-06-27 20:03:22
【问题描述】:

我听说malloc() 根据分配的类型对齐内存。例如,来自Understanding and Using C Pointers一书:

分配的内存将根据指针的数据类型对齐。例如,一个四字节整数将分配在可被四整除的地址边界上。

如果我跟随,这意味着 int *integer=malloc(sizeof(int)); 将分配在可被四整除的地址边界上。即使没有在 malloc 上投射 (int *)

我在一个聊天服务器上工作;我读到了similar effectstructs。

我不得不问:从逻辑上讲,为什么地址边界本身在什么上可分很重要?使用地址 129 上的整数分配一组内存到 n*sizeof(int) 有什么问题?

我知道指针算术是如何工作的*(integer+1),但我不知道边界的重要性......

【问题讨论】:

  • 我可以确认,这本书确实误导性地说,逐字:动态内存是从堆中分配的。 [...] 但是,分配的内存将根据指针的数据类型对齐。
  • 见这里:gamedev.net/page/resources/_/technical/general-programming/… 这有点说明为什么对齐很重要以及分配器的选择。游戏大部分时间都在最大限度地利用计算机的性能,因此,我认为稍微看一下那篇文章是个好主意。看看Aligned Allocations 部分。在接近尾声时,它还显示了基准。
  • 如果您尝试取消引用指向 32 位 int 的未对齐指针(sparc,我在看您...),也存在 CPU 会发出硬件陷阱。
  • 在不知道标准内容的情况下,您可以立即判断该声明有问题。想想对 malloc() 的调用是什么样子的:malloc() 没有办法 知道指针的类型。
  • 嘿,是的,你是对的。关于 c++ 的运算符“new”的陈述可能是真的,但不是 malloc。 malloc 必须假设最坏的情况。

标签: c++ c pointers memory-management


【解决方案1】:

分配的内存将根据指针的数据对齐 输入。

如果您在谈论malloc,这是错误的。 malloc 不关心您如何处理数据,它会分配内存以适应最严格的本机实现类型。

来自标准:

如果分配成功返回的指针是适当对齐的,所以 可以将它分配给指向任何类型对象的指针 基本对齐要求,然后用于访问这样的 分配的空间中的对象或此类对象的数组(直到 空间被显式释放)

还有:

从逻辑上讲,为什么地址边界本身很重要 整除

由于底层机器的工作原理,访问未对齐的数据可能更昂贵(例如 x86)或非法(例如 arm)。这让硬件可以走捷径,提高性能/简化实施。

【讨论】:

    【解决方案2】:

    在许多处理器中,未对齐的数据会导致“陷阱”或“异常”(这与 C++ 编译器所理解的异常形式不同。即使在数据未对齐时不陷阱的处理器上) '未对齐,当数据未正确对齐时,它通常会更慢(例如,慢两倍)。因此,确保事物正确对齐符合编译器/运行时库的最大利益。

    顺便说一句,malloc(通常)不知道你在分配什么。 Insteat,malloc 会将所有数据(无论大小)对齐到某个合适的边界,该边界对于一般数据访问来说“足够好”——在现代操作系统/处理器组合中通常为 8 或 16 字节,在旧系统中为 4 字节.

    这是因为malloc 不知道您是使用char* p = malloc(1000); 还是double* p = malloc(1000);,所以它必须假设您存储的是double 或任何具有最大对齐要求的项目。

    【讨论】:

      【解决方案3】:

      对齐的重要性不是语言问题,而是硬件问题。有些机器无法读取未正确对齐的数据值。其他人可以这样做,但效率较低,例如,需要两次读取才能读取一个未对齐的值。

      【讨论】:

      • 这是最正确的答案。我添加 1) malloc 不知道指针引用的数据类型。 Malloc 无法判断它是在分配指向 2 个 2 字节整数还是 1 个 4 字节整数的指针。 2) Malloc 实现经常使用互锁指令来保证线程安全。这些通常需要对齐的数据。
      • @user3344003 告诉你声称是错误的答案都比这个更正确,它只告诉你为什么它是真的,如果它是真的,它不是。
      • @EJP 您的评论毫无意义。我正在回答他的主要问题“为什么地址边界本身可分割的内容很重要?”即,为什么对齐很重要。我没有说任何关于 malloc 的事情(事实上它必须分配到最严格的对齐方式,因为它对数据类型一无所知)。
      • 关键点是 1) 一些处理器无法访问未对齐的数据,以及 2) 大多数其他处理器在这样做时效率低下。 Ooga 对 malloc 关心的原因给出了一个简明的答案。断言 malloc 基于返回类型执行此操作是错误的。
      【解决方案4】:

      书名有误; malloc 返回的内存保证对于任何类型都正确对齐。即使您写了char *ch = malloc(37);,它仍然与int 或任何其他类型对齐。

      您似乎在问“什么是对齐?”如果是这样,那么已经有几个关于这个的问题了,例如here,或者来自 IBM here 的一个很好的解释。

      【讨论】:

        【解决方案5】:

        这取决于硬件。即使假设 int 是 32 位,malloc(sizeof(int)) 也可以返回可被 1、2 或 4 整除的地址。不同的处理器以不同的方式处理未对齐的访问。

        处理器不再直接从 RAM 中读取,这太慢了(需要数百个周期)。因此,当他们确实抓取 RAM 时,他们会以大块的形式抓取它,例如一次 64 个字节。如果您的地址未对齐,则 4 字节整数可能跨越两个 64 字节缓存行,因此您的处理器必须执行两次加载并修复结果。或者,工程师可能认为不需要构建硬件来修复未对齐的负载,因此处理器会发出异常信号:要么您的程序崩溃,要么操作系统捕获异常并修复操作(数百个浪费的周期)。

        对齐地址意味着您的程序可以很好地与硬件配合使用。

        【讨论】:

          【解决方案6】:

          因为它更快;大多数处理器喜欢对齐的数据。甚至,某些处理器无法访问未对齐的数据! (如果您尝试访问此数据,处理器可能会出现故障)

          【讨论】:

          • 你能给我一个处理器在非对齐数据上失败的例子吗?但是给我一些1980+的东西
          • @Nick 不要在旧事物中找到; ARM is one of this processors.
          • 谢谢。我想我试过了,没问题,但会再次检查并在此处更新。我有 gcc 打包结构,它们肯定可以工作。
          • 刚刚在三星cpu上检查过。创建 char x[1000],然后将 int * 放在 & x[1] 上。值被正确读取。不确定是 ARM CPU 处理它还是 gcc 进行了值重构,但它确实有效。
          猜你喜欢
          • 1970-01-01
          • 2022-01-15
          • 2021-12-03
          • 2013-05-18
          • 1970-01-01
          • 2012-04-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多