È possibile allocare grandi quantità di memoria virtuale in Linux?
Possibilmente. Ma potrebbe essere necessario configurarlo in modo che sia consentito:
Il kernel Linux supporta le seguenti modalità di gestione dell'overcommit
0 - Gestione euristica dell'overcommit. Gli overcommit evidenti di addressspace vengono rifiutati. Utilizzato per un sistema tipico. Garantisce che un'allocazione seriamente selvaggia fallisca consentendo al contempo l'overcommit di ridurre lo swapusage. root può allocare un po' più di memoria in questa modalità. Questa è l'impostazione predefinita.
1 - Sovrascrivi sempre. Appropriato per alcune applicazioni scientifiche. L'esempio classico è il codice che utilizza array sparsi e si affida solo alla memoria virtuale composta quasi interamente da zero pagine.
2 - Non esagerare. Il commit totale dello spazio degli indirizzi per il sistema non può superare swap + una quantità configurabile (l'impostazione predefinita è il 50%) di RAM fisica. A seconda della quantità che utilizzi, nella maggior parte delle situazioni ciò significa che un processo non verrà interrotto durante l'accesso alle pagine ma riceverà errori sull'allocazione della memoria a seconda dei casi.
Utile per le applicazioni che vogliono garantire che le loro allocazioni di memoria saranno disponibili in futuro senza dover inizializzare ogni pagina.
La politica di overcommit viene impostata tramite sysctl `vm.overcommit_memory'.
Quindi, se vuoi allocare più memoria virtuale di quanta ne hai memoria fisica, allora dovresti:
# in shell
sysctl -w vm.overcommit_memory=1
RLIMIT_AS La dimensione massima della memoria virtuale del processo (spazio indirizzo) in byte. Questo limite influisce sulle chiamate a brk(2), mmap(2) e mremap(2), che falliscono con l'errore ENOMEM al superamento di questo limite. Anche l'espansione automatica dello stack fallirà (e genererà un SIGSEGV che interrompe il processo se nessuno stack alternativo è stato reso disponibile tramite sigaltstack(2)). Poiché il valore è lungo, su macchine con una lunghezza di 32 bit questo limite è al massimo di 2 GiB oppure questa risorsa è illimitata.
Quindi, vorresti:
setrlimit(RLIMIT_AS, {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
});
Oppure, se non puoi concedere al processo il permesso di farlo, puoi configurarlo in modo persistente in /etc/security/limits.conf che influenzerà tutti i processi (di un utente/gruppo).
Ok, quindi mmap sembra supportare ... ma richiede un descrittore di file. ... potrebbe essere una vittoria ma non se devono essere supportati da un file ... non mi piace l'idea di allegare a un file
Non è necessario utilizzare un mmap supportato da file. C'è MAP_ANONYMOUS per questo.
Non sapevo quale numero inserire per la richiesta
Quindi usa null. Esempio:
mmap(nullptr, 256*GB, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
Detto questo, se hai configurato il sistema come descritto, allora new
dovrebbe funzionare altrettanto bene di mmap
. Probabilmente userà malloc
che probabilmente utilizzerà mmap
per grandi allocazioni come questa.
Suggerimento bonus:potresti trarre vantaggio dall'utilizzo di HugeTLB Pages.
Il valore di 256*GB
non rientra in un intervallo di tipo intero a 32 bit. Prova uint64_t
come un tipo di GB
:
constexpr uint64_t GB = 1024*1024*1024;
o, in alternativa, forzare la moltiplicazione a 64 bit:
char* p = new char[256ULL * GB];
OT:Preferirei questa definizione di GB
:
constexpr uint64_t GB = 1ULL << 30;
Per quanto riguarda il limite di memoria virtuale, vedi questa risposta.