環境:64位的centos7.2(3.10.0-327)或centos7.4(3.10.0-693),系統剛重啟過,無業務壓力,物理記憶體也足夠,還剩十幾G。
現象:
mmap每次申請4k記憶體頁,連續申請1024*1024次(共4G),成功,top 和 /proc/smaps 中可以看到占用4G左右物理記憶體。
然后,針對每個記憶體頁,呼叫munmap。 但是部分munmap失敗,error是12(ENOMEM)。 top 和 /proc/smaps中顯示,還占用1.6G物理記憶體。
疑問:
申請的時候是按頁的粒度成功分配的,釋放的時候也是按頁的粒度做的釋放,為什么munmap會報12(記憶體不足)?
另外,如果去掉(i%11==0 || i%197==0 || i%393==0)這個條件,則munmap不報錯。 但是,我并沒有跨頁釋放。
代碼:
#include <iostream>
#include <memory.h>
#include <sys/mman.h>
#include <errno.h>
#include <assert.h>
#define PAGE_SIZE 4096
#define PAGE_COUNT 1024*1024
int main()
{
std::string str;
void** table = new void*[PAGE_COUNT];
std::cout << "begin mmap..." << std::endl;
for (int i=0; i<PAGE_COUNT; i++) {
table[i] = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1 ,0);
assert(table[i] != MAP_FAILED);
memset(table[i], 1, PAGE_SIZE);
}
std::cout << "mmap finish. input any str and enter to begin munmap..." << std::endl;
std::cin >> str;
for(int i=0; i<PAGE_COUNT; i++) {
if (i%11==0 || i%197==0 || i%393==0)
continue;
if (munmap(table[i], PAGE_SIZE) != 0)
std::cout << errno << std::endl;
}
delete[] table;
std::cin >> str;
return 0;
}
uj5u.com熱心網友回復:
另外,如果去掉(i%11==0 || i%197==0 || i%393==0)這個條件,則munmap不報錯。 但是,我并沒有跨頁釋放。標紅的什么意思?
===========================================
No memory is available.
ENOMEM
The process's maximum number of mappings would have been exceeded. This error can also occur for munmap(), when unmapping a region in the middle of an existing mapping, since this results in two smaller mappings on either side of the region being unmapped.
ENOMEM
(since Linux 4.7) The process's RLIMIT_DATA limit, described in getrlimit(2), would have been exceeded.
uj5u.com熱心網友回復:
@bigpillow, 您標為綠色的一段話,指從一個大的mapping區域unmapping其中的一部分,會導致mapping區域分裂,進而增加mapping的個數。 “我并沒有跨頁釋放”,意思是我每次都是mmap 4k,然后munmap 這個4k,因此并沒有在4k頁面的中間去munmap一部分(比如munmap 3k)。 所以,應該不會導致mapping區域分裂。 那為什么會報ENOMEM的錯誤呢?而且,我發現linux內核版本從3.10.0 - 4.15.0 運行上述程式,都有這個問題,是內核的bug嗎?
uj5u.com熱心網友回復:
你這個table 的結構體好像有點問題,列印出來看看吧uj5u.com熱心網友回復:
改寫成C試了一下,確實出現了樓主所描述的所有問題,應該是內核方面的一個健壯性問題,估計沒有考慮到會有APP這么申請記憶體。uj5u.com熱心網友回復:
mmap申請的時候由于是連續的,被合并成一個了隔著釋放就會造成達到 vm.max_map_count了
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/273053.html
標籤:內核源代碼研究區
