linux 上的 malloc 特定地址或页面(指定一个 "minimum offset")

Malloc specific address or page (specify a "minimum offset") on linux

在 linux 上的 LuaJIT 中,所有 VM 内存内存必须低于 2GB 进程内存边界,因为内部指针始终为 32 位。因此我想自己管理更大的分配(使用 FFI 和 malloc,等等),例如用于大纹理、音频、缓冲区等

我现在想确保它们映射到 2GB 边界之上,因为这样它们就不会带走任何 VM 可管理内存。

有什么方法可以 mallocmmap(没有映射文件,或者可能在 SHM 中)专门在该地址之上分配一个指针?甚至不必占用 2gig,只需将我的指针映射到更高(=非 32 位)地址

分配一个 2 GB 的块。如果低于限制,再分配 2 GB(这个必须大于 2 GB,因为只有一个块大小可以容纳 2 GB 以下)。

/* Allocates size bytes at an address higher than address */
void *HighMalloc(size_t size, void *address) {
    size_t mysize = (size_t)address;
    void *y, *x;
    if (mysize < size) {
        mysize = size;
    }
    y = x = malloc(mysize);
    if (x < address) {
        /* The memory starts at a low address. 
         * mysize is so big that another block this size cannot fit 
         * at a low address. So let's allocate another block and 
         * then free the block that is using low memory. */
        x = malloc(mysize);
        free(y);
    }
    return x;
}

注:

如果size 小于address,则在第二个malloc 的低地址可能有足够的space。这就是为什么我在这些情况下增加分配的大小。所以不要用它来分配小内存块。分配一个大块,然后手动将其分成更小的块。

我唯一知道的(所以这可能不是最佳选择)是将 mmap 用于 Linux。在某些情况下,我不得不分配与特定值对齐的巨大内存块,所以我使用了它(因为在这里你可以指定内存块的地址和长度)但它需要实现一些内存管理器单元,因为现在你是将管理分配(和发布)。

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

详情请看这里:http://man7.org/linux/man-pages/man2/mmap.2.html

要使其不映射到任何文件,只需将 flags 设置为 MAP_ANONYMOUS:

MAP_ANONYMOUS

The mapping is not backed by any file; its contents are initialized to zero. The fd and offset arguments are ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANON) is specified, and portable applications should ensure this. The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is supported on Linux only since kernel 2.4.

如果 addr 为 NULL,那么系统会为您选择可用地址,但由于您要分配超过 2G 的空间,您将需要管理已分配页面的列表,以便了解哪些地址是用在2G以上。另请注意,如果您指定 addr=X,并且 mmap 将无法使用该地址,它不会失败,它只会选择另一个可以使用而没有任何失败指示的地址(除了returned 指针不等于 addr 的事实)。但是,您可以使用 MAP_FIXED 标志来强制执行您提供的地址,如果 mmap 无法使用它,它将失败(return MAP_FAILED)。

MAP_FIXED

Don't interpret addr as a hint: place the mapping at exactly that address. addr must be a multiple of the page size. If the memory region specified by addr and len overlaps pages of any existing mapping(s), then the overlapped part of the existing mapping(s) will be discarded. If the specified address cannot be used, mmap() will fail. Because requiring a fixed address for a mapping is less portable, the use of this option is discouraged.

编辑

请注意,不建议使用 MAP_FIXED,因为如描述所述

If the memory region specified by addr and len overlaps pages of any existing mapping(s), then the overlapped part of the existing mapping(s) will be discarded.

而且你甚至都不知道。更安全地检查 addr 是否等于 return 由 mmap 地址编辑。