如何分配与页面大小对齐的内存?

11

我需要分配内存,该内存应按页面大小对齐。 我需要将此内存传递给一个计算所有数据块异或的ASM代码。 我需要使用malloc()来完成此操作。


9
我需要使用 malloc() 完成这个任务。你为什么已经决定了解决方案呢? - David Heffernan
2
RTFM - r3mainer
5个回答

15

有相应的函数可以实现这一点,建议使用这些函数。

如果出于任何原因无法使用这些函数,则通常的做法是将块大小添加到分配大小中,然后使用整数运算技巧来对指针进行舍入。

类似于这样:

/* Note that alignment must be a power of two. */
void * allocate_aligned(size_t size, size_t alignment)
{
  const size_t mask = alignment - 1;
  const uintptr_t mem = (uintptr_t) malloc(size + alignment);
  return (void *) ((mem + mask) & ~mask);
}

这个还没有进行深入的测试,但是你会明白意思。

请注意,后续将无法确定指向要释放内存的正确指针。为了解决这个问题,我们需要添加一些额外的机制:

typedef struct {
  void *aligned;
} AlignedMemory;

AlignedMemory * allocate_aligned2(size_t size, size_t alignment)
{
  const size_t mask = alignment - 1;
  AlignedMemory *am = malloc(sizeof *am + size + alignment);
  am->aligned = (void *) ((((uintptr_t) (am + 1)) + mask) & ~mask);
  return am;
}

这种方法对指针进行了一些处理,使你可以使用free()释放指针,但是你需要通过引用aligned指针来获取正确对齐的指针。


1
@glglgl:做和malloc相同的事情。在返回给用户的地址之前的4个字节中写入原始地址。 - Damon
@AlterMann 呵呵。好的,因为我需要一个整数而不是指针。我的通常限制在这里不适用,void * 不会自动转换为 uintptr_t。 :) - unwind

12

我认为仅使用malloc是不可能的。你可以使用memalign():

char *data = memalign(PAGESIZE, alloc_size);

其中PAGESIZE是页面的大小,alloc_size是将要分配的内存大小。

页面的大小可以使用sysconf(_SC_PAGESIZE)来获取。


10

使用 posix_memalign 函数来获得已经对齐的内存。

注意:vallocmemalign 函数都已经过时。


2
请使用 valloc 替代 malloc - 它与 malloc 具有相同的函数签名,但它分配的内存是页面对齐的。请注意,您仍然需要使用 free() 释放内存。
还要注意,valloc 在技术上已经过时了,因此考虑使用 posix_memalign,尽管这不像 malloc 那样简单,因为它具有非常不同的函数签名。

valloc已被记录为过时,请勿使用! - Basile Starynkevitch
我认为 valloc 还将存在很长一段时间。请注意,它不仅适用于 Linux,还适用于 BSD/Mac OS X/等等。但是,为了完整起见,我已添加了一个关于使用更加繁琐的 posix_memalign 的注释。 - Paul R

0

// 面向Linux, // 看看我排列的诡计

我刚刚写了一个程序,需要分配硬件页面对齐的内存;以下是包含main()函数的程序正文

main()函数调用Func_a()函数,该函数调用Func_b()函数,后者又调用前面提到的Func_a()函数,以此类推......递归地进行并且没有停止条件,因此无限期地烧毁程序堆栈,最终导致SIGSEGV。

希望这能帮助你:

#include "Func_A.h"
#include "Func_B.h"


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define STACK_SIZE (1024 * 1024)

int main(void)
{
  // Allocate a 2nd stack for the SIG_SEGV signal handler
  long pgsz = sysconf(_SC_PAGESIZE);
  printf("Page size is %ld\n", pgsz);

  long stacksize = STACK_SIZE;

  long sigstkpages = (STACK_SIZE + (pgsz - 1) ) / pgsz;

  void* newstack = calloc(sigstkpages, pgsz);
  if (NULL == newstack)
  {
    perror("calloc()\n");
    exit(2);
  }
  newstack = (void*) (((((long) newstack) + (pgsz - 1)) / pgsz) * pgsz);
  void* newstackhigh = (void*) (((long) newstack) + (stacksize - 1));
  stacksize = (newstackhigh - newstack) + 1;
  printf("Stack size is %ld\n", stacksize);

  printf("New Stack spans %p-%p  (%ld pages)\n", newstack, newstackhigh, sigstkpages);

  a();
}

它的输出为:

页面大小为4096 堆栈大小为1048576 新堆栈跨越0x7f28435cd000-0x7f28436ccfff(256页) 分段错误(核心已转储)

在这里预期发生核心转储。


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