Encontré una gran explicación sobre smaps de información sobre smaps
A mi entender, pensé que
limpieza_compartida + suciedad_compartida + limpieza_privada + suciedad_privada = rss
Escribí un programa para verificarlo:
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);
}
Pero para mi sorpresa, el /proc/pid/smaps
es:
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
¿Hay algún problema con mi comprensión?
según la respuesta de Mat,
Las páginas del 6M que estás leyendo no pueden considerarse realmente limpias. Una página limpia es aquella que está sincronizada con su almacén de respaldo (lo que sea, un intercambio, un archivo, etc.).
.
Reescribo los códigos usando mmap, esta vez el resultado es el esperado :)
Primero cree un archivo ficticio:
time dd if=/dev/zero of=test.bin bs=30000000 count=1
nuevo 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
Respuesta1
En primer lugar, su código muestra un comportamiento indefinido ( cnt
se usa sin haber sido inicializado, lo mismo para los 6M principales que está leyendo sin inicializar), así que asegúrese de que su compilador realmente genere instrucciones que coincidan con su código: no es necesario. (Supongo que lo has comprobado).
Las páginas del 6M que estás leyendo no pueden considerarse realmente limpias. Una página limpia es aquella que está sincronizada con su almacén de respaldo (lo que sea, un intercambio, un archivo, etc.). Esas páginas no tienen nada que las respalde.
Tampoco están realmente sucios en el sentido habitual; después de todo, no han sido modificados.
Entonces, ¿qué está pasando aquí? Todas las páginas del bloque de 6M que solo estás leyendo están asignadas a la misma página, y esa página es la "página cero" (es decir, una página compartida (al menos en x86) que contiene 4k cero bytes).
Cuando el kernel recibe un error de página en una página anónima no asignada, y ese error es una lectura, se asigna en una página cero (la misma página cada vez). (Esto está en do_anonymous_page
in mm/memory.c
)
Este no es un mapeo "normal" (en el vm_normal_page
sentido), y no se contabiliza en los smaps
campos como nada compartido o privado ( smaps_pte_entry
in fs/proc/task_mmu.c
omite las páginas "especiales" por completo). Sin embargo, se contabiliza en RSS y Tamaño: desde la perspectiva del espacio de direcciones, estas páginas virtuales existen y han sido "usadas".
Si comienza a modificar (escribir en) cualquier página en esa área, obtendrá una asignación normal y adecuada con una página anónima (inicializada en cero en este caso específico, curiosamente, no se inicializará en cero si la página anterior (no -normal/falso) el mapeo no estaba en la página cero). (Ver do_wp_page
en mm/memory.c
.) En ese momento verás smaps
mostrar lo que esperas.
Tenga en cuenta que nada en C, POSIX ni ningún otro elemento garantiza que estas páginas contengan ceros, no puede confiar en eso. (En realidad, tampoco se puede confiar en eso en Linux; así es como está implementado en este momento, pero posiblemente podría cambiar).