一、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-hant/n/134673.html