Encontrei uma ótima explicação sobre smaps em informações sobre smaps
No meu entendimento, pensei que
limpeza_compartilhada + sujeira_compartilhada + limpeza_privada + sujeira_privada = rss
Eu escrevi um programa para verificar isso:
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);
}
Mas para minha surpresa, /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
Alguma coisa errada com meu entendimento?
de acordo com a resposta de Mat,
As páginas dos 6M que você está apenas lendo não podem ser consideradas limpas. Uma página limpa é aquela que está sincronizada com seu armazenamento de apoio (seja lá o que for, swap, um arquivo, etc.).
.
Reescrevi os códigos usando mmap, desta vez o resultado é o esperado :)
crie um arquivo fictício primeiro:
time dd if=/dev/zero of=test.bin bs=30000000 count=1
novo Código:
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);
}
gato /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
Responder1
Primeiro, seu código exibe um comportamento indefinido ( cnt
é usado sem ter sido inicializado, o mesmo para os 6M principais que você está lendo sem inicializar), portanto, certifique-se de que seu compilador realmente produza instruções que correspondam ao seu código: não é necessário. (Presumo que você tenha verificado isso.)
As páginas dos 6M que você está apenas lendo não podem ser consideradas limpas. Uma página limpa é aquela que está sincronizada com seu armazenamento de apoio (seja lá o que for, swap, um arquivo, etc.). Essas páginas não têm nada que as apóie.
Eles também não estão realmente sujos no sentido usual - afinal, eles não foram modificados.
Então, o que está acontecendo aqui? Todas as páginas no bloco de 6M que você está lendo apenas são mapeadas para a mesma página, e essa página é a "página zero" (ou seja, uma página compartilhada (pelo menos em x86) que contém 4k zero bytes).
Quando o kernel recebe uma falha de página em uma página anônima não mapeada, e essa falha é uma leitura, ele mapeia em uma página zero (a mesma página todas as vezes). (Isso está em do_anonymous_page
in mm/memory.c
)
Este não é um mapeamento "normal" (no vm_normal_page
sentido) e não é contabilizado nos smaps
campos como nada compartilhado ou privado ( smaps_pte_entry
in fs/proc/task_mmu.c
pula páginas "especiais" inteiramente). Porém, ele é contabilizado em RSS e tamanho: do ponto de vista do espaço de endereço, essas páginas virtuais existem e foram "usadas".
Se você começar a modificar (escrever em) qualquer página nessa área, ela obterá um mapeamento normal e adequado com uma página anônima (inicializada com zero neste caso específico, curiosamente - não será inicializada com zero se a anterior (não -normal/fake) o mapeamento não estava na página zero). (Veja do_wp_page
em mm/memory.c
.) Nesse ponto, você verá smaps
o que espera.
Observe que nada em C, POSIX ou qualquer outra coisa garante que essas páginas contenham zeros, você não pode confiar nisso. (Na verdade, você também não pode confiar nisso no Linux - é assim que está implementado agora, mas pode mudar.)