Search code examples
clinuxunixmallocposix

How to use malloc with madvise and enable MADV_DONTDUMP option


I'm looking to use madvise and malloc but I have always the same error:

madvise error: Invalid argument

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

The page size is 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;
}

Here's the command:

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

Output:

madvise error: Invalid argument


Solution

  • Your usage of sizeof is wrong; you are allocating only four bytes of memory (sizeof unsigned int), and calling madvise() with a size argument of 1M for the same chunk of memory.


    #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;
    }
    

    Output:


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

    UPDATE:

    And the other problem is that malloc() can give you non-aligned memory (probably with an alignment of 4,8,16,...), where madvice() wants page-aligned memory:


    #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;
    }
    

    OUTPUT:


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

    And the alignement requerement appears to be linux-specific:

    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).


    Finally:

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

    Which, of course, doesn't make sense. Malloc or posix_memalign add to your address space, making (at least) the VSIZ of your running program larger. What happens to the this space is completely in the hands of the (kernel) memory manager, driven by your program's references to the particular memory, with maybe a few hints from madvice.