【问题标题】:Is there a linux equivalent of _aligned_realloc是否有 _aligned_realloc 的 linux 等价物
【发布时间】:2021-03-01 05:30:07
【问题描述】:

是否有相当于_aligned_realloc 的linux 版本?

我想使用 realloc,这样我就不必每次调整数据大小时都对其进行 memcpy。我被mmap困住了吗?我只使用过一次 mmap 有没有推荐的实现内存的方法可以调整几次?我假设我不能将 mmap 与aligned_alloc 混合使用,并且我必须在第一次调整大小时执行memcpy? (或始终使用 mmap)

下面的 realloc 并不总是对齐。我在 (64bit) linux 下使用 gcc 和 clang 进行了测试

#include<cstdlib>
#include<cstdio>
#define ALIGNSIZE 64
int main()
{
    for(int i = 0; i<10; i++)
    {
        void *p = aligned_alloc(ALIGNSIZE, 4096);
        void *p2 = realloc(p, 4096+2048); //This doesn't always align
        //void *p3 = aligned_alloc(ALIGNSIZE, 4096/24); //Doesn't need this line to make it unaligned. 

        if (((long)p & (ALIGNSIZE-1)) != 0 || ((long)p2 & (ALIGNSIZE-1)) != 0)
            printf("%d %d %d\n", i, ((long)p & (ALIGNSIZE-1)) != 0, ((long)p2 & (ALIGNSIZE-1)) != 0);
    }
}

【问题讨论】:

  • 不,realloc() 不保证任意对齐,只保证机器字。
  • 您能在您的问题中解释为什么您需要特定的对齐方式吗? malloc、realloc 等保证返回适合作为指向当前平台上任何数据类型的指针的地址。这意味着在 64 位系统上,它至少与适合 64 位值的地址对齐,即 8 字节的倍数。
  • @Bodo 但不适用于 32/64/128 字节对齐的 simd 适合的数据。
  • @epx 不是“机器字”,而是最大自然对齐。这通常比一个词更重要。
  • @EricStotch 在您的情况下,这可能并不重要,但如果有足够的背景信息可用,通常有人可能会为您的用例提出完全不同的解决方案。这就是为什么在问题中提供此信息很有用。这也将帮助其他有类似问题的人理解您的问题并确定它是否符合他们的用例。这就是为什么我建议将您评论中的信息添加到问题中。

标签: c++ c linux realloc memory-alignment


【解决方案1】:

不,在 C++、POSIX 标准和 GNU C 库中都没有标准替代方案。

这是一个仅使用标准函数的概念证明:

void*
aligned_realloc_optimistic(
    void* ptr, std::size_t new_size, std::size_t alignment)
{
    void* reallocated = std::realloc(ptr, new_size);
    return is_aligned(reallocated, alignment) // see below
        ? reallocated
        : aligned_realloc_pessimistic(reallocated, new_size, new_size, alignment);
        // see below
}

正如 cmets 中所指出的:这有一个警告,在最坏的情况下,std::realloc 可能无法重用分配,并且恰好返回未对齐的指针,然后我们分配了两次。

我们可以通过无条件地分配、复制和释放来跳过重新分配尝试,这消除了双重分配的最坏情况和无分配的最佳情况:

void*
aligned_realloc_pessimistic(
    void* ptr, std::size_t new_size, std::size_t old_size, std::size_t alignment)
{
    void* aligned = std::aligned_alloc(alignment, new_size);
    std::memcpy(aligned, ptr, old_size);
    std::free(ptr);
    return aligned;
}

这样做的明显问题是我们必须知道常规重新分配不需要的旧大小。

通过依赖系统特定的功能,我们可以保持避免分配和避免双重分配的最佳情况,也不需要知道旧的大小:

void*
aligned_realloc_glibc(
    void* ptr, std::size_t new_size, std::size_t alignment)
{
    auto old_size = malloc_usable_size(ptr); // GNU extension
    return old_size >= new_size && is_aligned(ptr, alignment)
        ? ptr
        : aligned_realloc_pessimistic(ptr, new_size, old_size, alignment);
}

上面用到的辅助函数:

bool is_aligned(void* ptr, std::size_t alignment)
{
    std::size_t space = 1;
    return std::align(alignment, space, ptr, space);
}

【讨论】:

  • 有时会进行多次重新分配...也许从一开始就使用aligned_alloc、memcpy 和free 会更好?
  • @Anonymous1847 我想这取决于realloc 能够避免分配的可能性。这是乐观的方法。如果有办法测试realloc是否会预先分配,我们既可以利用它,又可以避免两次分配的情况。
  • 如果我错了,请纠正我,但是这种“概念证明”不是危险的吗?被std::align 重新调整的指针将不能是std::freed,因为它不是任何分配函数(std::aligned_alloc、std::realloc 等)返回的同一个指针
  • @Human-Compiler 指针不会被std::align 调整,因为它没有被给予调整空间。
  • 啊,我明白了。标准是否保证size 的0 值不会只返回nullptr?
【解决方案2】:

我被 mmap 困住了吗?

如果您想要最大的灵活性,没有比使用平台的低级分配机制更好的方法了。

在这种情况下,您需要mremap(),可能需要MREMAP_MAYMOVE。它完全满足您的需求(如果您需要比页面更大的对齐方式,则需要手动处理)。

【讨论】:

    猜你喜欢
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 2021-03-29
    • 2011-01-16
    • 2020-09-20
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多