一、madvise函数
madvise
函数是Linux系统提供的一个操作系统调用(system call),用于控制系统内存管理。调用madvise
函数可以对指定的内存区域设置适当的使用策略,从而优化系统整体性能和内存利用率。
使用方法如下:
int madvise(void *addr, size_t len, int advice);
其中addr
参数指向欲改变的内存区域的首地址;len
参数代表欲改变内存区域的大小(以字节为单位);advice
参数可选,表示这段内存的用途,例如准备随后写入数据,可以选择MADV_WILLNEED
等。
二、madvise是什么意思
madvise
函数的主要作用是告诉内核,此区域的使用情况。它告诉内核在下一次内存缺页异常(Page Fault)发生时如何处理这个区域的页面。在没有使用madvise
函数的情况下,当进程访问不存在于内存中的虚拟地址时,内核将会生成一个Page Fault异常,并进入到中断处理程序进行处理。在处理结束后,内核会重载页面到内存或者把页面标识为无效。这个过程需要花费一定的时间。madvise
的目标是为了减少这个时间。
下面是几种advice
参数的作用:
MADV_NORMAL
:默认参数,没有特殊含义。MADV_RANDOM
:告诉内核此区域的访问方式是随机的。MADV_SEQUENTIAL
:告诉内核此区域的访问方式是顺序访问。MADV_WILLNEED
:告诉内核此区域需要预加载。常用于进程即将使用的数据,可以减少Page Fault的产生。MADV_DONTNEED
:告诉内核此区域的数据即将不再使用,一旦内存紧张,可以把这块内存立即释放。
三、madvise变向缺页检测怎么过
madvise
变向缺页检测,是madvise
优化内存利用率的一种技术。在使用大型内存区域时,很容易遇到内存限制的问题。如果采用传统的缺页处理方案,系统可能会把程序整个挂起来等待内存分配完成,这种情况下,程序的性能会受到很大的影响。
madvise
变向缺页检测的原理是先将内存区域设为内存映射区(或暂时存储提供页面的密集数组)。当访问内存区域时,操作系统会发现它并没有分配实际内存,此时,系统并不立即分配内存,而是等待其他内存释放后再分配。这样可以避免程序阻塞,提高程序性能,减少Page Fault数。
mmap+hugepage优化实例1
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/mman.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
int main(void) {
int fd;
void* p = mmap(NULL, 2*1024*1024, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, -1, 0);
if (p == MAP_FAILED) {
printf("errno=%d\n", errno);
return -1;
}
printf("virtual space is allocated\n");
while (getchar());
munmap(p, 2*1024*1024);
return 0;
}
mmap+hugepage优化实例2
void* alloc_hugepage(size_t size) {
void* p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, -1, 0);
if (p == MAP_FAILED) {
return NULL;
}
return p;
}
int main() {
void* p = alloc_hugepage(2*1024*1024);
if (p == NULL) {
printf("alloc hugepage failed!\n");
return -1;
}
printf("virtual space is allocated.\n");
while (getchar());
munmap(p, 2*1024*1024);
printf("virtual space is freed.\n");
return 0;
}
四、madvise hugepage是什么
madvise hugepage
是Linux内核提供的一种优化内存利用率的技术。由于一些特殊的应用程序需要使用大量内存,但一般的系统进程只会使用小块内存,所以Linux内核提供了HugePage技术。HugePage允许一个进程使用大块的内存页,这些页的大小都是2MB或者1GB。这些大页(或超级页面)虽然没有能很好地减少缺页异常,但它们极大地减少了TLB缺失率,从而使程序的性能得到提升。
使用HugePage的步骤是:
- 检查系统是否支持HugePage(内核版本大于2.6.32)。
- 检查系统是否配置了HugePage,如果没有,需要手动修改内核参数。
- 按照HugePage的方式编写程序。
HugePage可以通过标准的
mmap
调用获得。在系统启动时,机器统计了可以用于映射的物理内存数,然后自动创建一定数量的超级页面。
madvise+hugepage优化实例
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#define LENGTH (2*1024*1024)
#define HUGE_SIZE (2*1024*1024)
#define HUGE_MASK (HUGE_SIZE - 1)
int main(int argc, char** argv) {
void* ptr;
int pagemap_fd;
char pagemap_file[BUFSIZ];
int page_frame_number, pageshift;
if (argc == 2) {
ptr = mmap(NULL, LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if(ptr == MAP_FAILED) {
perror("Memory map failed");
return EXIT_FAILURE;
}
page_frame_number = ((unsigned long)ptr & ~(HUGE_MASK)) >> pageshift;
pageshift = getpagesize();
sprintf(pagemap_file, "/proc/self/pagemap");
pagemap_fd = open(pagemap_file, O_RDONLY);
if(pagemap_fd < 0) {
perror("Unable to open /proc/self/pagemap");
return EXIT_FAILURE;
}
if (pread(pagemap_fd, &page_frame_number, sizeof(int), page_frame_number*sizeof(int)) != sizeof(int)) {
fprintf(stderr, "Failed to read pagemap\n");
close(pagemap_fd);
munmap(ptr, LENGTH);
return EXIT_FAILURE;
}
close(pagemap_fd);
printf("page frame number: %d\n", page_frame_number);
} else {
ptr = mmap(NULL, LENGTH, PROT_READ|PROT_WRITE, MAP_HUGE_2MB|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if(ptr == MAP_FAILED) {
perror("Memory map failed");
return EXIT_FAILURE;
}
page_frame_number = ((unsigned long)ptr & ~(HUGE_MASK)) >> pageshift;
pageshift = getpagesize();
sprintf(pagemap_file, "/proc/self/pagemap");
pagemap_fd = open(pagemap_file, O_RDONLY);
if(pagemap_fd < 0) {
perror("Unable to open /proc/self/pagemap");
return EXIT_FAILURE;
}
if (pread(pagemap_fd, &page_frame_number, sizeof(int), page_frame_number*sizeof(int)) != sizeof(int)) {
fprintf(stderr, "Failed to read pagemap\n");
close(pagemap_fd);
munmap(ptr, LENGTH);
return EXIT_FAILURE;
}
close(pagemap_fd);
printf("page frame number: %d, HugePage\n", page_frame_number);
}
while (getchar());
munmap(ptr, LENGTH);
return EXIT_SUCCESS;
}