如何将 malloc 与 madvise 一起使用并启用 MADV_DONTDUMP 选项

How to use malloc with madvise and enable MADV_DONTDUMP option

我想使用 madvisemalloc,但我总是遇到同样的错误:

madvise error: Invalid argument

我尝试使用 MADV_DONTDUMP 在我的二进制文件中保存一些 space 但它没有用。

页面大小为 4096。

int main(int argc, char *argv[])
{
    void *p_optimize_object;
    unsigned int optimize_object_size = 4096*256;

    optimize_object_size = ((optimize_object_size / 4096) + 1) * 4096;
    printf("optimize_object_size = %d\n", optimize_object_size);
    p_optimize_object = malloc(optimize_object_size);
    if (madvise(p_optimize_object, optimize_object_size, MADV_DONTDUMP | MADV_SEQUENTIAL) == -1)
    {
        perror("madvise error");
    }
    printf("OK\n");
    return 0;
}

命令如下:

$ gcc -g -O3 madvice.c  && ./a.out

输出:

madvise error: Invalid argument

你不能,即使你可以在某些情况下使用某些标志(并且你在这里尝试使用的标志应该相对无害),你也不应该这样做。 madvise 从比 malloc 给你的更低级别分配的内存上操作,并且从 malloc 弄乱内存可能会破坏 malloc。

如果你想要一些可以调用 madvise 的内存块,你应该使用 mmap 获得它。

你对sizeof的用法是错误的;您仅分配了四个字节的内存(sizeof unsigned int),并为同一块内存调用了大小参数为 1M 的 madvise()。


#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>


int main(int argc, char *argv[])
{
    void *p_optimize_object;
    unsigned int optimize_object_size = 4096*256;

    optimize_object_size = ((optimize_object_size / 4096) + 1) * 4096;
    printf("optimize_object_size = %d\n", optimize_object_size);
    p_optimize_object = malloc(sizeof(optimize_object_size));
    fprintf(stderr, "Allocated %zu bytes\n",  sizeof(optimize_object_size));

    if (madvise(p_optimize_object, optimize_object_size, MADV_WILLNEED | MADV_SEQUENTIAL) == -1)
    {
        perror("madvise error");
    }
    printf("OK\n");
    return 0;
}

输出:


optimize_object_size = 1052672
Allocated 4 bytes
madvise error: Invalid argument
OK

更新:

另一个问题是 malloc() 可以为您提供非对齐内存(可能对齐 4,8,16,...),而 madvice() 需要页面对齐内存:


#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>


int main(int argc, char *argv[])
{
    void *p_optimize_object;
    unsigned int optimize_object_size = 4096*256;
    int rc;

    optimize_object_size = ((optimize_object_size / 4096) + 1) * 4096;
    printf("optimize_object_size = %d\n", optimize_object_size);
#if 0
    p_optimize_object = malloc(sizeof(optimize_object_size));
    fprintf(stderr, "Allocated %zu bytes\n",  sizeof(optimize_object_size));

#elif 0
    p_optimize_object = malloc(optimize_object_size);
    fprintf(stderr, "Allocated %zu bytes\n",  optimize_object_size);
#else
    rc = posix_memalign (&p_optimize_object, 4096, optimize_object_size);
    fprintf(stderr, "Allocated %zu bytes:%d\n",  optimize_object_size, rc);
#endif
    // if (madvise(p_optimize_object, optimize_object_size, MADV_WILLNEED | MADV_SEQUENTIAL) == -1)
    if (madvise(p_optimize_object, optimize_object_size, MADV_WILLNEED | MADV_DONTFORK) == -1)
    {
        perror("madvise error");
    }
    printf("OK\n");
    return 0;
}

输出:


$ ./a.out
optimize_object_size = 1052672
Allocated 1052672 bytes:0
OK

对齐要求似乎是 linux 特定的:

Linux Notes The current Linux implementation (2.4.0) views this system call more as a command than as advice and hence may return an error when it cannot do what it usually would do in response to this advice. (See the ERRORS description above.) This is non-standard behavior.

The Linux implementation requires that the address addr be page-aligned, and allows length to be zero. If there are some parts of the speci‐ fied address range that are not mapped, the Linux version of madvise() ignores them and applies the call to the rest (but returns ENOMEM from the system call, as it should).


最后:

I tried to use the MADV_DONTDUMP to save some space in my binaries but it didn't work.

这当然没有意义。 Malloc 或 posix_memalign 添加到您的地址 space,使(至少)您的 运行 程序的 VSIZ 更大。 this space 会发生什么完全掌握在(内核)内存管理器的手中,由您的程序对特定内存的引用驱动,maybe 来自 madvice 的一些提示.

I tried to use the MADV_DONTDUMP to save some space in my binaries but it didn't work.

再次仔细阅读 madvise(2) man 页面。

地址应该是页对齐的。 malloc的结果一般不是page aligned(page size往往是4Kbytes,但是看sysconf(3) for SC_PAGESIZE). Use mmap(2) to ask for a page-aligned segment in your virtual address space.

您不会在二进制 executable. You'll just save space in your core dump, see core(5). And core dumps should not happen. See signal(7) (read also about segmentation fault and undefined behaviour) 中保存任何 space

要禁用核心转储,请考虑 setrlimit(2) with RLIMIT_CORE (or the ulimit -c bash builtin 在您的终端 运行 a bash shell).