/proc/pid/maps의 PSS에 대해 혼란스럽습니다.

/proc/pid/maps의 PSS에 대해 혼란스럽습니다.

나는 smap에 대한 훌륭한 설명을 하나 찾았습니다. 스맵에 대한 정보

내 이해로는, 나는 그렇게 생각했다.

shared_clean + shared_dirty + private_clean + private_dirty = 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

내 이해에 문제가 있나요?


Mat의 답변에 따르면,

당신이 읽고 있는 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 0바이트를 포함하는 공유(적어도 x86에서는) 페이지).

커널이 매핑되지 않은 익명 페이지에서 페이지 오류를 받고 해당 오류가 읽기인 경우 제로 페이지(매번 동일한 페이지)에 매핑됩니다. (이것은 do_anonymous_page에 있습니다 mm/memory.c.)
이것은 "일반적인" 매핑이 아니며(의미에서 ) 필드에서 공유 또는 비공개 항목으로 vm_normal_page간주되지 않습니다 ( in 에서는 "특수" 페이지를 완전히 건너뜁니다). 하지만 RSS 및 크기에서는 고려됩니다. 주소 공간 관점에서 보면 이러한 가상 페이지가 존재하고 "사용"되었습니다. 해당 영역의 페이지 수정(쓰기)을 시작하면 익명 페이지와의 적절하고 정상적인 매핑을 얻게 됩니다(이 특정 경우에는 0으로 초기화됩니다. 흥미롭게도 이전(비 -정상/가짜) 매핑이 제로 페이지에 적용되지 않았습니다). ( 참조 ) 이 시점에서 예상한 대로 표시되는 것을 볼 수 있습니다 .smapssmaps_pte_entryfs/proc/task_mmu.c
do_wp_pagemm/memory.csmaps

C, POSIX 또는 다른 어떤 것도 이러한 페이지에 0이 포함되도록 보장하지 않으므로 이에 의존할 수 없습니다. (실제로 Linux에서도 이에 의존할 수는 없습니다. 이것이 현재 구현된 방식이지만 아마도 변경될 수 있습니다.)

관련 정보