如何确保mmap()& mremap()永远不会耗尽免费RAM?

时间:2014-04-29 23:14:05

标签: linux mmap

我尝试通过mmap() /dev/shm上的/dev/shm文件解决此问题,并且可以查询/dev/shm上的可用空间以确定是否有足够的可用内存(也称为免费{ {1}})可用于下一个mmap()和/或mremap()操作。但是,以下示例程序显示mremap()不可信;它似乎不尊重,例如原始MAP_POPULATE的初始mmap()?并mmap()本身似乎做懒惰的地图人口?至少当我只有8GB RAM可用时,它似乎很愉快(没有错误)mmap() 256GB文件!为什么?也许是因为ftruncate()允许我在/ dev / shm上创建一个256GB的文件,大小只有8GB!为什么呢?

#define _GNU_SOURCE
#include <sys/mman.h>
#include <assert.h>                                       
#include <stdio.h>
#include <stdint.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

// $ gcc -o dev-shm dev-shm.c && ./dev-shm
// /dev/shm/ free: 7824 MB, /dev/shm/mytemp.txt size:      1 MB; after ftruncate(     1MB)
// /dev/shm/ free: 7823 MB, /dev/shm/mytemp.txt size:      1 MB; after      mmap(     1MB)
// /dev/shm/ free: 7823 MB, /dev/shm/mytemp.txt size:      2 MB; after ftruncate(     2MB)
// /dev/shm/ free: 7822 MB, /dev/shm/mytemp.txt size:      2 MB; after      mmap(     2MB)
// /dev/shm/ free: 7822 MB, /dev/shm/mytemp.txt size:      3 MB; after ftruncate(     3MB)
// /dev/shm/ free: 7822 MB, /dev/shm/mytemp.txt size:      3 MB; after    mremap(     3MB)
// Question #1: Why does mremap() not reduce /dev/shm free?
//
// /dev/shm/ free: 7824 MB, /dev/shm/mytemp.txt size:      1 MB; after ftruncate(     1MB)
// /dev/shm/ free: 7823 MB, /dev/shm/mytemp.txt size:      1 MB; after      mmap(     1MB)
// /dev/shm/ free: 7823 MB, /dev/shm/mytemp.txt size:      2 MB; after ftruncate(     2MB)
// /dev/shm/ free: 7822 MB, /dev/shm/mytemp.txt size:      2 MB; after      mmap(     2MB)
// /dev/shm/ free: 7822 MB, /dev/shm/mytemp.txt size: 262144 MB; after ftruncate(262144MB)
// /dev/shm/ free: 7822 MB, /dev/shm/mytemp.txt size: 262144 MB; after    mremap(262144MB)
// Question #2: How can a 256GB file exist on /dev/shm?
//
// /dev/shm/ free: 7824 MB, /dev/shm/mytemp.txt size:      1 MB; after ftruncate(     1MB)
// /dev/shm/ free: 7823 MB, /dev/shm/mytemp.txt size:      1 MB; after      mmap(     1MB)
// /dev/shm/ free: 7823 MB, /dev/shm/mytemp.txt size: 262144 MB; after ftruncate(262144MB)
// /dev/shm/ free:    0 MB, /dev/shm/mytemp.txt size: 262144 MB; after      mmap(262144MB)
// /dev/shm/ free:    0 MB, /dev/shm/mytemp.txt size: 263168 MB; after ftruncate(263168MB)
// /dev/shm/ free:    0 MB, /dev/shm/mytemp.txt size: 263168 MB; after    mremap(263168MB)
// Question #3: How can mmap() MAP_POPULATE a 256GB file?

uint64_t get_dev_shm_free(const char * function, uint64_t size_mb) {
    struct statvfs mystatvfs; assert(0 == statvfs("/dev/shm/", &mystatvfs));
    uint64_t available = mystatvfs.f_bsize * mystatvfs.f_bfree;
    struct stat mystat; assert(0 == stat("/dev/shm/mytemp.txt", &mystat));
    uint64_t filesize = mystat.st_size;
    printf("/dev/shm/ free: %4.0f MB, /dev/shm/mytemp.txt size: %6.0f MB; %s(%6luMB)\n", available / 1024.0 / 1024.0, filesize / 1024.0 / 1024.0, function, size_mb);
    return available;
}

void grow_dev_shm_file(uint64_t size_mb_1, uint64_t size_mb_2, uint64_t size_mb_3) {
    unlink("/dev/shm/mytemp.txt");

    int fd = open("/dev/shm/mytemp.txt", O_RDWR | O_CREAT, 0600); assert(-1 != fd);
    int value = ftruncate(fd, size_mb_1 * 1024 * 1024); assert(-1 != value);
    get_dev_shm_free("after ftruncate", size_mb_1);
    void * mymem =  mmap(NULL, size_mb_1 * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE | MAP_POPULATE, fd, 0); assert(MAP_FAILED != mymem);
    get_dev_shm_free("after      mmap", size_mb_1);
    close(fd);

    fd = open("/dev/shm/mytemp.txt", O_RDWR | O_CREAT, 0600); assert(-1 != fd);
    value = ftruncate(fd, size_mb_2 * 1024 * 1024); assert(-1 != value);
    get_dev_shm_free("after ftruncate", size_mb_2);
    value = munmap(mymem, size_mb_1 * 1024 * 1024); assert(-1 != value);
    mymem =  mmap(NULL, size_mb_2 * 1024 * 1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE | MAP_POPULATE, fd, 0); assert(MAP_FAILED != mymem);
    get_dev_shm_free("after      mmap", size_mb_2);
    close(fd);


    fd = open("/dev/shm/mytemp.txt", O_RDWR | O_CREAT, 0600); assert(-1 != fd);
    value = ftruncate(fd, size_mb_3 * 1024 * 1024); assert(-1 != value);
    get_dev_shm_free("after ftruncate", size_mb_3);
    mymem = mremap(mymem, size_mb_2 * 1024 * 1024, size_mb_3 * 1024 * 1024, MREMAP_MAYMOVE); assert(MAP_FAILED != mymem);
    get_dev_shm_free("after    mremap", size_mb_3);
    close(fd);

    munmap(mymem, size_mb_3 * 1024 * 1024);
    unlink("/dev/shm/mytemp.txt");
}

int main(void) {
    grow_dev_shm_file(1,          2,          3); printf("Question #1: Why does mremap() not reduce /dev/shm free?\n\n");
    grow_dev_shm_file(1,          2, 256 * 1024); printf("Question #2: How can a 256GB file exist on /dev/shm?\n\n");
    grow_dev_shm_file(1, 256 * 1024, 257 * 1024); printf("Question #3: How can mmap() MAP_POPULATE a 256GB file?\n\n");
}

0 个答案:

没有答案