2015-04-04 4 views
1

В linux malloc ведет себя оппортунистически, только резервное копирование виртуальной памяти по реальной памяти при первом доступе. Можно ли было бы изменить calloc так, чтобы он также вел себя так (выделение и обнуление страниц при первом доступе)?Сделать calloc оппортунистическим

+1

Обратите внимание, что для больших фрагментов 'calloc' в Linux/glibc уже является оппортунистическим (использует тот же самый вызов MAP_PRIVATE | MAP_ANONYMOUS' mmap, что и новомодные страницы обещают читать как нули). –

ответ

2

Это не функция malloc(), которая делает ее «оппортунистической». Это особенность ядра, с которым malloc() не имеет ничего общего.

malloc() запрашивает ядро ​​для пощечины памяти каждый раз, когда ему требуется больше памяти для выполнения запроса, и это ядро, которое говорит «Да, конечно, у вас есть» каждый раз, без фактического обеспечения памяти. Это также ядро, которое обрабатывает последующие ошибки страницы, поставляя нулевые страницы памяти. Обратите внимание, что любая память, которую ядро ​​поставляет, будет уже обнулена из-за соображений безопасности, поэтому она одинаково хорошо подходит для malloc() и для calloc().

То есть, если реализация calloc() портит это, безоговорочно обнуляя сами страницы (создавая ошибки страницы, которые побуждают ядро ​​фактически поставлять память), он будет иметь такое же «оппортунистическое» поведение, как malloc().


Обновление:

В моей системе, следующая программа успешно выделяет 1 TiB в системе только 2 ГиБ памяти (!):

#include <stdlib.h> 
#include <stdio.h> 

int main() { 
    size_t allocationCount = 1024, successfullAllocations = 0; 
    char* allocations[allocationCount]; 
    for(int i = allocationCount; i--;) { 
     if((allocations[i] = calloc(1, 1024*1024*1024))) successfullAllocations++; 
    } 
    if(successfullAllocations == allocationCount) { 
     printf("all %zd allocations were successfull\n", successfullAllocations); 
    } else { 
     printf("there were %zd failed allocations\n", allocationCount - successfullAllocations); 
    } 
} 

Я думаю, его с уверенностью сказать, что по крайней мере, реализация calloc() на моем ящике ведет себя «оппортунистически».

+0

«любая память, которую ядро ​​поставляет, будет уже нулевым».Это прекрасно и денди, но как насчет памяти, которая возвращается в кучу «free», а затем «calloc'ed снова? –

+0

Спасибо, я не знал, что ядро ​​обычно нули всю память. Это не объясняет, что я принял приложение (которое я не написал) и изменил вызовы на 'calloc' на' malloc', и он разбился. Я предполагаю, что это связано с тем, что выделенная память не была обнулена, а приложение предполагало, что это будет. –

+0

@ н.м. Любая память, которая не была возвращена ядру, должна быть нулевана 'calloc()', если она будет использоваться для нового выделения. Однако, если реализация 'free()' возвращает память в ядро ​​(через 'munmap()' или 'sbrk()'), новое сопоставление, созданное с помощью 'mmap()' или 'sbrk()', снова будет равным нулю из ядра. – cmaster

1

Из соответствующего раздела /proc/sys/vm/overcommit_memory в proc:

объем памяти в настоящее время выделяется на систему. Собранная память представляет собой сумму всей памяти, которая была распределена процессами, даже если она еще не была «использована» ими. Процесс, который выделяет 1 ГБ памяти (используя malloc (3) или аналогичный), но касается только 300 МБ этой памяти, будет отображаться только с использованием 300 МБ памяти, даже если у него есть адресное пространство, выделенное для всего 1 ГБ. Это 1 ГБ - это память, которая была «зафиксирована» виртуальной машиной и может быть использована в любое время приложением распределения. При включенном строгом перекомпоновке в системе (режим 2/proc/sys/vm/overcommit_memory) распределения, превышающие CommitLimit (подробно описанные выше), не будут разрешены. Это полезно, если нужно гарантировать, что процессы не сбой из-за нехватки памяти, как только память будет успешно распределена.

Хотя явно не сказал, я думаю похож здесь означает calloc и realloc. Так calloc уже ведет себя оппортунистически как malloc.

+1

'calloc' сильно отличается от' malloc'. 'calloc' гарантирует, что возвращаемая память инициализируется нулем. 'malloc' не делает. Если вы не знаете, что 'calloc' удается обнулить страницы, не касаясь их, или каким-то образом отказывается от обнуления до первого доступа, вы должны подумать дважды, прежде чем делать такие обобщения. –