C++指针对齐的目的是什么?

3

我现在正在阅读计算机视觉开源库OPENCV的源代码。我对这个函数感到困惑:

#define CV_MALLOC_ALIGN 16
void* fastMalloc( size_t size )
{
    uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);
    if(!udata)
        return OutOfMemoryError(size);
    uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);
    adata[-1] = udata;
    return adata;
}

/*!
  Aligns pointer by the certain number of bytes

  This small inline function aligns the pointer by the certian number of bytes by
  shifting it forward by 0 or a positive offset.
 */
template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp))
{
    return (_Tp*)(((size_t)ptr + n-1) & -n);
}

fastMalloc 用于为指针分配内存,它会调用 malloc 函数,然后调用 alignPtr。我不太理解为什么在分配内存后要调用 alignPtr。我的基本理解是通过这样做,机器可以更快地找到指针。在互联网上是否可以找到一些关于这个问题的参考资料?对于现代计算机来说,执行这个操作仍然必要吗?任何想法都将不胜感激。


可能是为了缓存或特殊指令。 - Micka
2个回答

1
一些平台要求某些类型的数据出现在特定的字节边界上(例如:有些编译器需要将指针存储在4字节边界上)。这被称为对齐,需要在对象的数据内部和可能末尾增加额外的填充。
如果编译器未找到适当的对齐方式,则可能会中断,或者读取该数据时可能会存在性能瓶颈(因为需要读取两个块以获取相同的数据)。
针对评论进行编辑:
程序请求的内存通常由内存分配器处理。其中一个内存分配器是固定大小分配器。即使请求的内存小于特定大小,固定大小分配器也会返回指定大小的块。因此,基于这个背景,让我尝试解释这里发生了什么。
uchar* udata = (uchar*)malloc(size + sizeof(void*) + CV_MALLOC_ALIGN);

这将分配与 memory_requested + random_size 相等的内存量。 这里的 random_size 是填补间隙以使其适合固定分配方案的指定大小。
uchar** adata = alignPtr((uchar**)udata + 1, CV_MALLOC_ALIGN);

这是尝试将指针与上述特定边界对齐的过程。


1
不仅是编译器,CPU也是如此。 - deviantfan
2
但是对象是通过malloc分配的,它已经返回了一个指针适当对齐[...]任何类型的对象(C99, 7.20.3p1)。 - ouah
@ouah:这可能是为了缓存对齐目的而将某些内容对齐到更大的边界上。 - Bill Lynch
2
“对于任何类型的对象”并不包括例如使用movaps指令加载的浮点数,这些需要例如16字节对齐。 - Anteru

1

它分配的块比要求的稍微大一点。

然后它将adata设置为下一个已分配字节的地址(添加一个字节,然后向上舍入到下一个正确对齐的地址)。

接着,它在新地址之前存储原始指针。我假设这将被用于释放最初分配的块。

然后我们返回新地址。

只有当CV_MALLOC_ALIGN是比malloc保证的更严格的对齐方式时(例如缓存行),这才有意义。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接