【问题标题】:Why there is difference by 16 byte between allocated variables' addresses? [duplicate]为什么分配的变量地址之间存在 16 个字节的差异? [复制]
【发布时间】:2017-03-05 17:58:02
【问题描述】:

为什么要对齐 8 个字节(在 64 位系统上是 16 个字节)?这种对齐的原因是什么?

示例:

int* ptr1 = new int;
int* ptr2 = new int;
int* ptr3 = new int;

cout << ptr1 << " " << ptr2 << " " << ptr3 << endl;
cout << ptr2 - ptr1 << endl;

输出:

0x15cbc20 0x15cbc40 0x15cbc60  
8

【问题讨论】:

  • 实际上,查看您提供的输出,您分配的 int 相隔 32 个字节。
  • 完全取决于使用什么内存分配算法。分配的块不太可能与请求的类型大小完全匹配,但至少是对齐的,或者获取与默认分配器一起使用的最小内存块。
  • 对齐已完成,因此 CPU 可以更快地从主内存中读取
  • 指针的区别不是8个字节,而是8个整数。无论如何,只分配一些大小,如 32、64 或 128 字节可能会提高分配速度并最大限度地减少内存碎片。谁在堆上分配单个整数?
  • 您需要一本关于计算机如何工作的书! :D

标签: c++ c++11


【解决方案1】:
int* ptr1 = new int;
int* ptr2 = new int;
int* ptr3 = new int;

第一,不能保证这些语句将分配与sizeof(int) 相关的连续内存地址。

这种对齐的原因是什么?

因为 CPU 有缓存来访问堆分配的数据,并且这些缓存经过优化,可以对 32 位或 64 位指针使用字节对齐的访问,具体取决于目标架构。

【讨论】:

    【解决方案2】:

    实际上有两件事通常负责:

    • 对齐(其他答案已处理)
    • 簿记信息

    当您请求 4 字节(例如)内存时,您的底层内存分配器(无论选择的 operator new(...) 使用什么)可能会使用一些额外的字节来存储一些簿记信息。看好解释here

    簿记信息通常是 delete 工作的原因,而无需告诉它请求的原始内存大小。

    例如:

    void* Malloc(std::size_t size){
         //Allocator searches for free memory
         auto FreeList = GetNextFreeNodeOfAtLeast(size + 16);
    
         //Rounds the requested size to the ceil of CPU word size
         size = RoundToWordAlignment(size);
    
         //Allocate with an extra 16 bytes for bookkeeping
         void* Memory = FreeList->Allocate(size + 16);
    
         //Use the Upper 16bytes... some implementations use lower..
         auto info = static_cast<MallocInformation*>(Memory + size);
    
         //Create an Info object so that `Free` or operator delete can use to free memory
         new(info) MallocInformation(size, FreeList, ....);
    
         //Return the Memory
         return Memory;
    }
    

    分配给您的每块内存都附有一些积压的信息。内存分配器有许多不同的工作方式,有些具有单个指针的簿记信息,指向管理内存的某个主结构。

    C++ 标准不要求连续的内存分配是连续的,也没有指定它们之间有多少内存“间隙”。

    【讨论】:

    • CPU 字是 2 个字节,对吗?因此,这种对齐对于开销大小来说并不那么重要。还是有一些额外的对齐,不仅仅是单词?
    【解决方案3】:

    无法保证动态分配的对象会被相邻存储(即使在相邻对齐的地址中)。您的分配器碰巧分配了内存 8*sizeof(int)(您的系统上为 32)字节,这是一个实现细节。

    operator new 通常(尽管不能保证,这是另一个实现细节)使用malloc 实现。使用malloc 分配内存时,无法请求特定对齐。这就是为什么它保证分配内存适合任何内置类型,即sizeof(maxalign_t) 边界。因此,对于一个典型的实现,我不会意外地发现 8 或 16 个字节的对齐方式。

    【讨论】:

      猜你喜欢
      • 2017-10-13
      • 1970-01-01
      • 2015-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-09
      • 1970-01-01
      • 2012-12-02
      相关资源
      最近更新 更多