Испытываю ли я подкачку по запросу, когда не изменяю значения только что созданного массива?
Я изучаю управление памятью ОС и только что узнал о виртуальной памяти и о том, как ее можно реализовать с помощью подкачки по запросу .
Я сделал эту простую программу:
#include<stdio.h>
#include<stdlib.h>
int main(void){
int x=0;
scanf("%d",&x);
if(x==1){
int *a=malloc(1073741824*sizeof(int));
while(1){
for(size_t i=0;i<1073741824;i++){
a[i]=1;
}
}
}
else if(x==2){
int *b=malloc(1073741824*sizeof(int));
while(1);
}
return 0;
}
Она имеет
Один выделил массив и продолжает изменять его значения.
Другой выделил массив, но не меняет его значений.
Как я и ожидал, после запуска первого варианта память программы увеличивается примерно до
Я правильно понимаю?
2 ответа
Пейджинг по запросу - это когда вы обращаетесь к страницам памяти, которых нет в кэше страниц Linux. Например, если вы используете отображение памяти, вы можете получить доступ к файлу на диске, как если бы он находился в ОЗУ. Когда вы разыменовываете указатель с отображением в память, Linux сначала проверяет кеш страницы на наличие данных; если страницы нет в кеше, происходит сбой страницы и загружаются недостающие страницы с диска. Ваша программа не видит весь доступ к диску по запросу, происходящий за кулисами.
Пейджинг по запросу не имеет отношения к новому вызову, поскольку на диске ничего нет. То, что вы видите, называется чрезмерной приверженностью. Linux не выделяет память при вызове; он лежит и всегда возвращает указатель независимо от того, может он удовлетворить запрос или нет. Память фактически выделяется только тогда, когда (если) вы обращаетесь к ней. Если вы просите 4 ГБ памяти, но ничего не делаете с ними, на самом деле ничего не выделяется.
Неудивительно, что ложь не всегда получается. Linux может фактически не удовлетворить потребности программы в памяти, но программа не может знать, потому что
malloc()
не вернул NULL. Это похоже на авиакомпанию, которая забронирует больше рейсов. Авиакомпания выдает вам билет, но когда вы появляетесь в аэропорту, они говорят вам, что у них закончились места, и выгоняют вас с рейса. Вы пытаетесь получить доступ к выделенной вами памяти, и Linux паникует, вызывает OOM-убийцу и начинает убивать процессы, чтобы освободить память. Кого это убивает? Может ваш процесс. Может быть, тебя пощадили, а другие умрут. Достаточно сказать, что чрезмерная приверженность - спорная особенность.
Если вы включите оптимизацию кода, сгенерированный код не будет вызывать
malloc
вообще.
.LC0:
.string "%d"
main:
sub rsp, 24
mov edi, OFFSET FLAT:.LC0
xor eax, eax
lea rsi, [rsp+12]
mov DWORD PTR [rsp+12], 0
call __isoc99_scanf
mov eax, DWORD PTR [rsp+12]
cmp eax, 1
je .L4
cmp eax, 2
je .L6
xor eax, eax
add rsp, 24
ret
.L4:
mov eax, 1073741824
.L3:
sub rax, 1
jne .L3
jmp .L4
.L6:
jmp .L6
Чтобы предотвратить это, сделайте указатель изменчивым:
int main(void){
int x=0;
scanf("%d",&x);
if(x==1){
int * volatile a=malloc(1073741824*sizeof(int));
while(1){
for(size_t i=0;i<1073741824;i++){
a[i]=1;
}
}
}
else if(x==2){
int * volatile b=malloc(1073741824*sizeof(int));
while(1);
}
return 0;
}
Теперь он должен malloc в обоих случаях:
.LC0:
.string "%d"
main:
sub rsp, 24
mov edi, OFFSET FLAT:.LC0
xor eax, eax
lea rsi, [rsp+4]
mov DWORD PTR [rsp+4], 0
call __isoc99_scanf
mov eax, DWORD PTR [rsp+4]
cmp eax, 1
je .L10
cmp eax, 2
je .L11
xor eax, eax
add rsp, 24
ret
.L10:
mov edi, 1
sal rdi, 32
call malloc
mov QWORD PTR [rsp+8], rax
.L4:
mov eax, 1073741824
.L3:
mov rdx, QWORD PTR [rsp+8]
sub rax, 1
jne .L3
jmp .L4
.L11:
mov edi, 1
sal rdi, 32
call malloc
mov QWORD PTR [rsp+8], rax
.L6:
jmp .L6