Размер анонимного mmap и сегмента данных

У меня сложилось впечатление, что с тех пор, как системы Unix представили анонимные mmap, RLIMIT_DATA стал несколько бесполезным, поскольку адресное пространство mmap не входит в размер сегмента данных. В частности, реализация glibc malloc() использует анонимные mmap для больших выделений.

Тем не менее, мое тестирование показало, что, по крайней мере, в не очень древних системах Linux, анонимные mmap включены в сегмент данных. Рассмотрим тестовую программу ниже:


/* Test mmap and ulimit.  */

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

int print_memstat()
{
    char line[80];
    FILE *f = fopen("/proc/self/status", "r");
    if (!f)
        return -1;
    while (1) {
    if (!fgets(line, 80, f))
        break;
    if (strncmp(line, "VmSize", 6) == 0
        || strncmp(line, "VmRSS", 5) == 0
        || strncmp(line, "VmData", 6) == 0)
        printf("%s", line);
    }
    fclose(f);
    return 0;
}



int main(int argc, char* argv[])
{
    if (argc < 3) {
        printf("Usage: %s MODE SIZE_IN_MiB\nwhere\n\
    MODE=0: Anonymous mmap\n\
    MODE=1: mmap of a temporary file\n\
    MODE=2: malloc\n", argv[0]);
        return 0;
    }
    int mode = atoi(argv[1]);
    long n = atol(argv[2]); // Mem in MiB

    n *= 1024*1024;

    void *p;
    int fd;
    char template[] = "/tmp/mmaptestXXXXXX";

    switch (mode) {
    case 0:
        p = mmap(NULL, n, PROT_READ|PROT_WRITE, 
               MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
        if (p == MAP_FAILED) {
            perror("anonymous mmap failed");
            return 1;
        }
        break;
    case 1:
        fd = mkstemp(template);
        if (fd == -1) {
            perror("mkstemp failed");
            return 1;
        }
        unlink(template);
        if (ftruncate(fd, n) == -1) {
           perror("ftruncate failed");
           return 1;
        }
        p = mmap(NULL, n, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
        if (p == MAP_FAILED) {
           perror("mmap failed");
           return 1;
        }
        break;
    case 2:
        p = malloc(n);
        if (!p) {
           perror("malloc failed");
           return 1;
        }
        break;
    default:
        printf("MODE must be 0, 1 or 2\n");
        return 0;
    }
    memset(p, 42, n); // Bump up RSS to approx VSS
    print_memstat();
    return 0;
}

Протестировано на RHEL5, 6 и Ubuntu 12.04. Во всех этих случаях при выделении с использованием анонимного mmap() (MODE=0 и MODE=2 при использовании glibc malloc()) размер раздела данных (VmData) увеличивается, чтобы включить выделение.

РЕДАКТИРОВАТЬ: Некоторые дальнейшие эксперименты показывают, что в то время как анонимные mmap () действительно увеличивают размер раздела данных в поле VmData в /proc/[PID]/status, ограничения RLIMIT_DATA применяются только к размеру кучи, то есть brk() распределения и не анонимный mmap(). Aargh!

Теперь мой вопрос: как долго это происходило в Linux и насколько оно переносимо на другие системы Unix? Т.е. другие Unix также включают анонимные mmap в размер сегмента данных?

0 ответов

Другие вопросы по тегам