对于一个研究项目,我必须使用
malloc()
和 free()
编写 mmap()
和 munmap()
的重新实现代码。
我在最后一个 Ubuntu 上运行。对于我的测试,我使用命令
time -v
(来自/usr/bin/time
)它向我显示了很多关于我的程序的信息,包括内存。这里有一些例子:
所以我们可以看到
Minor page faults
对应于回收页数根据我们的使用情况而变化,但特别是如果我们在 free()
之后使用 malloc()
回收页数返回到它们的初始数量而不是我重新实现的案例:
在我的
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
)。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()
这样的功能...我发现了我的问题。在我的主要任务中,我连续不断地执行 malloc() 和 free() 一个接一个。当系统执行
munmap()
时,它会尝试通过不立即删除 mmap()
分配的页面来进行优化,以便稍后重用它。但是,这仍然会导致在后续调用 mmap()
. 期间创建新页面
为了解决这个问题,
free()
需要留下一个剩余的页面,这样munmap()
就不会在循环中被调用。
我的解释不是很清楚,欢迎提供更多细节。