記憶體對映佔物理記憶體統計

2021-09-19 23:45:55 字數 3962 閱讀 3982

系統:centos

語言:c++

背景:搜尋引擎的索引資料很大,分布式之後,每個索引節點的索引資料還是比較大,佔了大概100g左右,全放在記憶體中是不現實的,而且因為我們的搜尋引擎不穩定,單個節點容易出現崩潰的問題,所以索引資料需要落盤到磁碟上,這樣雖然會使單個搜尋節點更加穩定,但是磁碟比記憶體的缺點就更加顯露無疑了,那就是訪問資料太慢,所以我們就想使用mmap的預讀策略和檔案的磁碟快取來解決缺頁錯誤導致從磁碟訪問速度過慢的問題。

我們使用mmap的方式開啟磁碟檔案,mmap會返回乙個指標,對指標的某個位置的修改就會自動通過flush執行緒將修改同步到磁碟檔案上,不過有個小點需要注意,那就是不是修改後立刻同步,這樣會造成讀寫磁碟頻率過高,而是mmap內部有自己的演算法寫夠多少個byte才會將記憶體快取區的內容回寫到磁碟上。

mmap的原型void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);大家自己通過man mmap自己體會,介紹幾個注意的點。

1. 如果addr不為空,意味著自己分配好了空間帶進去,如果為空,意味著讓mmap自動分配記憶體空間。

2. flags那個引數一般有兩個選項,

1.map_shared:共享的,修改檔案會影響其他程式,當然其他程式也會影響你。

2.map_private,隨便改,沒關係,這段空間就是你的了。

3. offset 必須是個4096能整除的數。

4. fd帶入-1表示匿名對映,具體細節因為我沒有設計所以我並不關心。

那麼在說說檔案快取,有個很明顯的區別,如果我們開啟乙個很久沒有開啟的檔案,然後做mmap對映從頭到尾去將每乙個byte加起來,這種做法叫『掃』。我們第一次掃乙個大檔案會花費很長的時間,第二次掃就會花費短一些的時間,這裡面的差別就是檔案快取造成的,那麼什麼時候會快取檔案呢。分兩種,一、剛剛建立好的檔案會在檔案快取中,二、剛剛操作過的檔案會在檔案快取中。

檔案快取的基本單位是頁,一頁通常是4096位元組也就是4kb大小,使用sysconf(_sc_page_size)方法可以檢視本機頁大小。

每次檔案快取都是以頁為單位的,舉例說明,如果我第一次訪問了很久的檔案的第50頁,那麼系統會將35-55頁的30頁快取起來,那麼拿第50頁會發生一次缺頁中斷然後快取30頁,如果我再訪問第51頁,那麼因為有檔案快取所以就不會再去訪問磁碟,直接從快取中拿出第51頁,所以就不會發生缺頁中斷。從而提高了程式的效率。

那麼mmap返回的指標跟頁有什麼關係呢?簡單的說,比方mmap返回的指標叫做ptr,那麼ptr[0-4095]就是第一頁,ptr[4096-8191]就是第二頁。

再介紹幾個工具和函式。

1.free -m shell命令列裡輸出即可。-m是以mb為單位輸出。具體含義網上很多。我們主要關心最後一列的cache,這一列表示檔案快取的大小。

2.dd if=/dev/zero of=bean  count=1024000 bs=1024也是shell命令列,作用是生成乙個大檔案,這個工具好像被用來製作開機啟動指令碼,反正很厲害的樣子。我們這裡大致介紹一下,if是輸入檔案目錄,/dev/zero是乙個有無限個0的檔案,of是輸出檔案,count是多少塊,bs是塊大小。用這個命令就能生成乙個1gb的名為bean的檔案,檔案內容為全0。

3./proc/pid/smaps,這是乙個檔案,其中pid是執行程序的程序號,smaps裡面表示著所有記憶體對映的資訊。我們不用關係一些.so庫,我們只關心我們開啟的檔案。細節含義網上到處都是,我只說我們用到的,size表示檔案總大小,rss表示載入到記憶體多大,即可。

6. posix_fadvise,也是乙個系統呼叫,他的含義是告訴磁碟快取我不需要這個檔案了,請把記憶體釋放出來給其他應用使用,函式原型int posix_fadvise(int fd, off_t offset, off_t len, int advice);需要詳細資訊的自己man一下,其中advice有兩個標誌位posix_fadv_willneed意味著告訴磁碟快取我以後要用這個檔案請不要換出,posix_fadv_dontneed告訴磁碟快取這個檔案我不需要了,請幫我清理出去。

7. top的shr記憶體占用,表明了所有使用mmap開啟的檔案所占用的記憶體,包括堆,棧,大的new,so,mmap開啟的檔案等等,其中需要注意的是因為棧只有乙個棧針(棧頂指標)所以棧非棧頂釋放其實是不會釋放的。

其中,free計算的記憶體和mincore計算的記憶體一致,top和smaps計算的記憶體一致。free計算的記憶體包含預載入進來的記憶體。但是smaps裡面只包含訪問的那一頁的記憶體,即smaps訪問一頁rss就加4k,但是mincore訪問一頁需要在記憶體中載入很多頁進來。但是預載入的這些頁是不算在程序記憶體中的,所以top和smaps程序記憶體不會顯示預載入的頁面,因為top和smaps是程序級別的,而free和mincore計算的是系統級別的。

下面放入一段程式,該程式是自己寫的乙個小例子,很low,不過能反應問題,這個程式可以達到訪問某頁,遍歷所有頁,清空檔案的檔案快取這4個功能。

#include #include #include #include #include #include #include #include #include #include #include #include using namespace std;

int clear_file_cache(const char *filename)

int fd = open(filename, o_rdonly);

if( fd < 0 )

//clear cache by posix_fadvise

if( posix_fadvise(fd,0,st.st_size,posix_fadv_dontneed) != 0)

else

return 0;

}void getpageinfo(char *pdat, size_t len, uint32_t page_count, unsigned char *pvec)

uint32_t hitcnt = 0;

uint32_t i = 0;

for (; i < page_count; ++i)

}struct rusage m_rusage;

getrusage(rusage_self, &m_rusage);

cout << hitcnt << ", " << page_count << ", " << m_rusage.ru_majflt << endl;

}int main(int argc, char *ar**)

int fd = open(ar**[1], o_rdwr);

if (fd == -1)

struct stat stat;

off_t size = lseek(fd, 0, seek_end);

char *pdat = (char *)mmap(null, size, prot_read | prot_write, map_private, fd, 0);

uint32_t page_size = sysconf(_sc_pagesize);

uint32_t page_count = (size + page_size - 1) / page_size;

unsigned char *pvec = new unsigned char[page_count];

if (argc == 3 && strcmp(ar**[2], "all") == 0)

cout << sum << endl;

}else if (argc == 3)

getpageinfo(pdat, size, page_count, pvec);

delete pvec;

sleep(1000);

return 0;

}

編譯方式就是很簡單的g++ main.cpp -o main,第乙個引數帶入檔名,第二個引數帶入all表示遍歷,clear表示清空,數字表示需要訪問哪乙個,輸出為0,25600,0的格式,第乙個0表明載入了多少頁在記憶體中,25600表示總共有多少頁,第三個0表示發生了多少次缺頁中斷。

物理記憶體連續記憶體分配

記憶體管理的要求 共享 訪問相同記憶體 記憶體管理方式 重定位,relocation,段位址 偏移 分段,segmentation,資料,堆疊分成三塊,每段連續 分頁,paging,記憶體分為最基本的單位,房子的磚塊 虛擬儲存 virtual memory,linux採用按需頁式虛擬儲存 邏輯位址空...

記憶體管理 物理記憶體 虛擬記憶體

記憶體管理 物理記憶體 pc上有三條匯流排,分別是資料匯流排 位址匯流排和控制匯流排。32位的cpu的定址能力為4gb 2 32 個位元組。使用者最多 可以使用4gb的真實的物理記憶體。記憶體管理 虛擬記憶體 windows的所有程式 包括ring0層和ring3層的程式 可以操作的都是虛擬記憶體。...

python threadpool的記憶體占用問題

先說結論 在使用多執行緒時,不要使用threadpool,應該使用threading,尤其是資料量大的情況。因為threadpool會導致嚴重的記憶體占用問題!對比threading和threadpool的記憶體占用 coding utf 8 import time import osimport ...