Некоторые распределители ленивы? - PullRequest
9 голосов
/ 14 мая 2009

Я написал C-программу для Linux, которая распределяет память по памяти, запускает ее в цикле, и TOP не показывает никакого потребления памяти.

тогда я что-то сделал с этой памятью, и TOP показал потребление памяти.

Когда я использую malloc, действительно ли я "получаю память" или есть "ленивое" управление памятью, которое дает мне память только, если / когда я ее использую?

(Существует также опция, которую TOP знает только о потреблении памяти, когда я ее использую, поэтому я не уверен в этом ..)

Спасибо

Ответы [ 6 ]

17 голосов
/ 14 мая 2009

В Linux malloc запрашивает память с помощью sbrk () или mmap () - так или иначе, ваше адресное пространство немедленно расширяется, но Linux не назначает реальные страницы физической памяти до первой записи на соответствующую страницу. Вы можете увидеть расширение адресного пространства в столбце VIRT, а фактическое использование физической памяти - в RES.

5 голосов
/ 14 мая 2009

Это начинается немного не по теме (а затем я свяжу это с вашим вопросом), но то, что происходит, похоже на то, что происходит, когда вы запускаете процесс в Linux. При разветвлении существует механизм, называемый копировать при записи, который копирует пространство памяти для нового процесса только тогда, когда память записывается. Таким образом, если раздвоенный процесс exec представляет собой новую программу, вы сэкономили накладные расходы на копирование памяти исходных программ.

Возвращаясь к вашему вопросу, идея похожа. Как уже отмечали другие, запрос памяти немедленно возвращает вам пространство виртуальной памяти, но фактические страницы выделяются только при записи в них.

Какова цель этого? Это в основном делает неправильную память более или менее постоянной операцией Big O (1) вместо операции Big O (n) (аналогично тому, как планировщик Linux распределяет свою работу вместо того, чтобы делать это одним большим блоком).

Чтобы продемонстрировать, что я имею в виду, я выполнил следующий эксперимент:

rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc 

real    0m0.005s
user    0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef 

real    0m0.558s
user    0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites 

real    0m0.006s
user    0m0.000s
sys 0m0.008s

Программа bigmalloc выделяет 20 миллионов целых, но ничего с ними не делает. deadbeef записывает по одному int на каждую страницу, в результате чего 19531 пишет, а justwrites выделяет 19531 целое и обнуляет их. Как вы можете видеть, выполнение deadbeef занимает в 100 раз больше времени, чем bigmalloc, и примерно в 50 раз дольше, чем просто сценарии.

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

return 0;

}

.

#include <stdlib.h>    

int main(int argc, char **argv) {

int *big = malloc(sizeof(int)*20000000); // allocate 80 million bytes

// immediately write to each page to simulate all at once allocation

// assuming 4k page size on 32bit machine

for ( int* end = big + 20000000; big < end; big+=1024 ) *big = 0xDEADBEEF ;    

return 0;

}

.

#include <stdlib.h>

int main(int argc, char **argv) {

int *big = calloc(sizeof(int),19531); // number of writes

return 0;
}
3 голосов
/ 14 мая 2009

Да, память не отображается в вашем пространстве памяти, если вы не коснетесь его. При неправильном использовании памяти будут настроены только таблицы подкачки, чтобы они знали, что при возникновении ошибки страницы в выделенной памяти, память должна быть сопоставлена.

1 голос
/ 14 июля 2009

Да, обратите внимание на флаги VirtualAlloc ,

MEM_RESERVE
MEM_COMMIT

.

Хех, но для Linux или любой POSIX / BSD / SVR # системы, vfork (), существует уже давно и предоставляет функциональные возможности.

Функция vfork () отличается от fork () только в том, что дочерний процесс может поделиться кодом и данными с вызывающий процесс (родительский процесс). это значительно ускоряет клонирование с риском для целостности родительский процесс, если vfork () используется не по назначению.

Использование vfork () для любых целей кроме как прелюдия к немедленному вызов функции из exec family или _exit () не рекомендуется.

Функция vfork () может использоваться для создавать новые процессы без полностью копирование адресного пространства старого процесс. Если раздвоенный процесс просто будем называть exec, пространство данных скопировано от родителя к ребенку fork () не используется. Это особенно неэффективно в постраничной среда, делая vfork () особенно полезно. В зависимости от размер родительского пространства данных, vfork () может дать значительный улучшение производительности по сравнению с fork ().

1 голос
/ 15 мая 2009

Эта функция называется overcommit - ядро ​​"обещает" вашу память, увеличивая размер сегмента данных, но не выделяет ему физическую память. Когда вы касаетесь адреса в этом новом пространстве, страница процесса сбрасывается в ядро, которое затем пытается отобразить на нем физические страницы.

0 голосов
/ 14 мая 2009

Вы используете оптимизацию компилятора? Может быть, оптимизатор удалил выделение, так как вы не используете выделенные ресурсы?

...