我找到了一個關於 smap 的很好的解釋 有關 smap 的信息
據我了解,我認為
共用清潔 + 共用清潔 + 私人清潔 + 私人清潔 = RSS
我寫了一個程式來驗證一下:
void sa();
int main(int argc,char *argv[])
{
sa();
sleep(1000);
}
void sa()
{
char *pi=new char[1024*1024*10];
for(int i=0;i<4;++i) { //dirty should be 4M
for(int j=0;j<1024*1024;++j){
*pi='o';
pi++;
}
}
int cnt;
for(int i=0;i<6;++i) { //clean should be 6M
for(int j=0;j<1024*1024;++j){
cnt+=*pi;
pi++;
}
}
printf("%d",cnt);
}
但令我驚訝的/proc/pid/smaps
是:
09b69000-09b8c000 rw-p 00000000 00:00 0 [heap]
...
Size: 10252 kB
Rss: 10252 kB
Pss: 4108 kB //<----I thought it should be 10M
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB //<----I thought it should be 6M
Private_Dirty: 4108 kB
Referenced: 4108 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
我的理解有什麼問題嗎?
根據馬特的回答,
你僅僅閱讀的6M頁面並不能真正被認為是乾淨的。乾淨頁面是與其後備儲存(無論是交換、文件等)同步的頁面。
。
我用mmap重寫了程式碼,這次結果符合預期:)
首先建立一個虛擬檔案:
time dd if=/dev/zero of=test.bin bs=30000000 count=1
新代碼:
void sa(char *pi)
{
for(int i=0;i<4;++i) {
for(int j=0;j<1024*1024;++j){
*pi='a';
pi++;
}
}
//just to use it to avoid the following code will not optimized off by the compiler
int dummycnt=0;
for(int i=0;i<6;++i) {
for(int j=0;j<1024*1024;++j){
dummycnt+=*pi;
pi++;
}
}
printf("%d",dummycnt);
}
int main()
{
int fd = open("./test.bin",O_RDWR);
char *p = (char *)mmap(0,
1024*1024*10, //10M
PROT_READ|PROT_WRITE,
MAP_SHARED,
fd,
0);
sa(p);
sleep(10000);
}
貓 /proc/pid/smaps:
b6eae000-b78ae000 rw-s 00000000 08:05 134424 ..../test.bin
Size: 10240 kB
Rss: 10240 kB
Pss: 10240 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 6144 kB
Private_Dirty: 4096 kB
Referenced: 10240 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
答案1
首先,您的程式碼表現出未定義的行為(cnt
在未初始化的情況下使用,與您在未初始化的情況下閱讀的前6M 內容相同),因此請確保您的編譯器實際上輸出與您的程式碼符合的指令:它不必這樣做。 (我假設你已經檢查過了。)
你僅僅閱讀的6M頁面並不能真正被認為是乾淨的。乾淨頁面是與其後備儲存(無論是交換、文件等)同步的頁面。這些頁面沒有任何支援它們的內容。
從通常的意義上來說,它們也不是很髒——畢竟,它們沒有被修改過。
那麼這裡發生了什麼事?您僅讀取的 6M 區塊中的所有頁面都對應到同一頁面,並且該頁面是「零頁面」(即包含 4k 零位元組的共用(至少在 x86 上)頁面)。
當核心在未映射的匿名頁面上發生頁面錯誤且該錯誤是讀取時,它會對應到零頁面(每次都是同一頁)。 (這是在do_anonymous_page
中mm/memory.c
)
這不是一個“正常”映射(在某種意義上vm_normal_page
),並且不會在smaps
字段中被視為共享或私有任何內容(smaps_pte_entry
在 中fs/proc/task_mmu.c
完全跳過“特殊”頁面)。不過,它確實在 RSS 和大小中得到了考慮:從位址空間的角度來看,這些虛擬頁面存在並且已被「使用」。
如果您開始修改(寫入)該區域中的任何頁面,它將獲得一個正確的、帶有匿名頁面的正常映射(在這種特定情況下為零初始化,有趣的是 - 如果前一個(非-正常/假)映射不是到零頁)。 (請參閱do_wp_page
中mm/memory.c
。)此時您將看到smaps
顯示您所期望的內容。
請注意,C、POSIX 或其他任何內容都不能保證這些頁麵包含零,您不能依賴這一點。 (實際上你也不能在 Linux 上依賴它——這就是它現在的實現方式,但可以想像它可能會改變。)