为什么在使用 `munmap()` 后页面回收仍然存在?

问题描述 投票:0回答:1

对于一个研究项目,我必须使用

malloc()
free()
编写
mmap()
munmap()
的重新实现代码。

我在最后一个 Ubuntu 上运行。对于我的测试,我使用命令

time -v
(来自
/usr/bin/time
)它向我显示了很多关于我的程序的信息,包括内存。这里有一些例子:

  • time -v without using malloc and free

  • time -v using only malloc

  • time -v using malloc and free (libc)

所以我们可以看到

Minor page faults
对应于回收页数根据我们的使用情况而变化,但特别是如果我们在
free()
之后使用
malloc()
回收页数返回到它们的初始数量而不是我重新实现的案例:

  • time -v using my malloc and free

以下是我的一些代码,用于可视化我所做的事情。

在我的

malloc()
中:

static t_page *__alloc_page(size_t size)
{
    struct rlimit limit;
    t_page *page;

    getrlimit(RLIMIT_AS, &limit);
    if (size > limit.rlim_max)
        return (NULL);
    page = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (page == MAP_FAILED)
        return (NULL);
    ft_bzero(page, sizeof(t_page));
    page->size = size;
    page->used_size = sizeof(t_page);
    return (page);
}

在我的

free()
中:

static void __free_page(t_page *page)
{
    t_binding *binder = __get_binder(page);

    binder->count--;
    if (binder->pages == page)
        binder->pages = page->next;
    
    if (page->prev != NULL)
        page->prev->next = page->next;
    if (page->next != NULL)
        page->next->prev = page->prev;

    if (munmap(page, page->size) == -1)
        ft_putstr("free(): munmap error\n");
}

有关信息,我的尺寸始终是

getpagesize()
N * getpagesize()
)的倍数。

这是我做测试的方法

首先我将我的文件

malloc.c
free.c
等编译成一个动态库(
libmalloc.so
)。
然后我用后面的 main 构建了两个二进制文件。一个是用我的 malloc 编译的,另一个是用 libc 编译的。

clang main.c -o libc_malloc
clang main.c -D LIBMALLOC libmalloc.so -o my_malloc
#ifdef LIBMALLOC
# include "../includes/malloc.h"
#else
# include <stdlib.h>
#endif

int main(void)
{
    int i;
    char *addr;

    i = 0;
    while (i < 1024) 
    {
        addr = (char*)malloc(1024);
        addr[0] = 42;
        free(addr);
        i++; 
    }
    return (0);
}

我还有一个脚本,允许我使用名为

run.sh
:

的动态库运行我的二进制文件
#!/bin/sh
export LD_LIBRARY_PATH="."
export LD_PRELOAD="`pwd`/libmalloc.so"
$@

最后,我用

time -v
运行我的两个二进制文件,如下所示:

/usr/bin/time -v ./libc_malloc
./run.sh /usr/bin/time -v ./my_malloc

如何以极简的方式重现

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

int main(void)
{
    int i;
    char *addr;

    i = 0;
    #ifdef _MMAP_
        printf("mmap\n");
    #else
        printf("malloc\n");
    #endif
    while (i < 1024) 
    {
        #ifdef _MMAP_
            addr = mmap(NULL, 4 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
        #else
            addr = malloc(4 * getpagesize());
        #endif
        addr[0] = 42;
        #ifdef _MMAP_
            munmap(addr, 4 * getpagesize());
        #else
            free(addr);
        #endif
        i++; 
    }
    return (0);
}

将上面的主要内容复制到文件中(

main.c
)。
创建两个二进制文件如下:

clang main.c -o using_malloc
clang -D _MMAP_ main.c -o using_mmap

然后用

time -v
运行它们:

/usr/bin/time -v ./using_malloc
/usr/bin/time -v ./using_mmap

我试过的

在网上搜索时,我遇到了这篇文章,它与我的问题完全相同:
使用 munmap 时更高的页面回收
但是建议的解决方案不起作用(我不能使用它)。
我也不允许使用像

posix_madvise()
msync()
这样的功能...
无论如何,我都试过了,看看他们是否能解决我的问题,但没有成功。
我也跑了别人的项目。他的作品很好,而我们似乎在做同样的事情。
我错过了什么吗?

c malloc dynamic-memory-allocation free mmap
1个回答
0
投票

我发现了我的问题。在我的主要任务中,我连续不断地执行 malloc() 和 free() 一个接一个。当系统执行

munmap()
时,它会尝试通过不立即删除
mmap()
分配的页面来进行优化,以便稍后重用它。但是,这仍然会导致在后续调用
mmap()
.

期间创建新页面

为了解决这个问题,

free()
需要留下一个剩余的页面,这样
munmap()
就不会在循环中被调用。

我的解释不是很清楚,欢迎提供更多细节。

© www.soinside.com 2019 - 2024. All rights reserved.