Я нашел одно замечательное объяснение по поводу smaps от информация о smaps
Насколько я понимаю, я думал, что
общий_чистый + общий_грязный + частный_чистый + частный_грязный = 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
используется без инициализации, то же самое касается верхних 6 МБ, которые вы читаете без инициализации), поэтому убедитесь, что ваш компилятор действительно выводит инструкции, соответствующие вашему коду: это не обязательно. (Я предполагаю, что вы это проверили.)
Страницы в 6M, которые вы только читаете, не могут считаться чистыми. Чистая страница — это та, которая синхронизирована со своим резервным хранилищем (что бы это ни было, своп, файл и т. д.). Эти страницы не имеют ничего, что их поддерживает.
Они также не являются грязными в обычном смысле — в конце концов, они не были изменены.
Так что же здесь происходит? Все страницы в блоке 6 МБ, который вы только читаете, отображаются на одну и ту же страницу, и эта страница является «нулевой страницей» (т. е. общей (по крайней мере на x86) страницей, которая содержит 4 Кб нулевых байтов).
Когда ядро получает ошибку страницы на неотображенной анонимной странице, и эта ошибка является чтением, оно отображает нулевую страницу (одну и ту же страницу каждый раз). (Это в в do_anonymous_page
) mm/memory.c
Это
не «нормальное» отображение (в том vm_normal_page
смысле), и не учитывается в smaps
полях как что-либо общее или частное ( smaps_pte_entry
в fs/proc/task_mmu.c
полностью пропускает «специальные» страницы). Однако оно учитывается в RSS и Size: с точки зрения адресного пространства эти виртуальные страницы существуют и «использовались».
Если вы начнете изменять (записывать) любую страницу в этой области, оно получит правильное, нормальное отображение с анонимной страницей (инициализированной нулем в этом конкретном случае, что интересно — она не будет инициализирована нулем, если предыдущее (ненормальное/поддельное) отображение не было на нулевую страницу). (См. do_wp_page
в mm/memory.c
.) В этот момент вы увидите smaps
то, что ожидаете.
Обратите внимание, что ни в C, ни в POSIX, ни где-либо еще нет гарантий, что эти страницы будут содержать нули, на это нельзя полагаться. (На самом деле, на это нельзя полагаться и в Linux — сейчас это реализовано именно так, но, возможно, ситуация изменится.)