一、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
#include
#include
#include
#include
#include
#include
#include
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
#include
#include
#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 > 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;
}
原創文章,作者:ZKTZ,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/134673.html
微信掃一掃
支付寶掃一掃