GNU/Linux >> Linux Esercitazione >  >> Linux

Come controllare la dimensione dell'heap per un processo su Linux

Penso che il tuo problema originale fosse quel malloc Impossibile allocare la memoria richiesta sul sistema.

Il motivo per cui ciò è accaduto è specifico del tuo sistema.

Quando un processo viene caricato, gli viene allocata memoria fino a un certo indirizzo che è il punto di interruzione del sistema per il processo. Oltre tale indirizzo la memoria non è mappata per il processo. Quindi, quando il processo "colpisce" il punto di "interruzione", richiede più memoria dal sistema e un modo per farlo è tramite la chiamata di sistema sbrk
malloc lo farebbe sotto il cofano ma nel tuo sistema per qualche motivo non è riuscito.

Potrebbero esserci molte ragioni per questo ad esempio:
1) Penso che in Linux ci sia un limite per la dimensione massima della memoria. Penso che sia ulimit e forse l'hai colpito. Controlla se è impostato su un limite
2) Forse il tuo sistema era troppo carico
3) Il tuo programma fa una cattiva gestione della memoria e ti ritroverai con una memoria frammentata quindi malloc non è possibile ottenere la dimensione del blocco richiesta.
4) Il tuo programma corrompe il malloc strutture di dati interne, ovvero cattivo utilizzo del puntatore
ecc


L'heap di solito è grande quanto la memoria virtuale indirizzabile sulla tua architettura.

Dovresti controllare i limiti attuali del tuo sistema con il ulimit -a comando e cerca questa riga max memory size (kbytes, -m) 3008828 , questa riga sul mio OpenSuse 11.4 x86_64 con ~3,5 GiB di RAM dice che ho circa 3 GB di RAM per processo.

Quindi puoi veramente testare il tuo sistema usando questo semplice programma per controllare la memoria massima utilizzabile per processo:

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

int main(int argc,char* argv[]){
        size_t oneHundredMiB=100*1048576;
        size_t maxMemMiB=0;
        void *memPointer = NULL;
        do{
                if(memPointer != NULL){
                        printf("Max Tested Memory = %zi\n",maxMemMiB);
                        memset(memPointer,0,maxMemMiB);
                        free(memPointer);
                }
                maxMemMiB+=oneHundredMiB;
                memPointer=malloc(maxMemMiB);
        }while(memPointer != NULL);
        printf("Max Usable Memory aprox = %zi\n",maxMemMiB-oneHundredMiB);
        return 0;
}

Questo programma ottiene la memoria con incrementi di 100 MiB, presenta la memoria attualmente allocata, alloca gli 0 su di essa, quindi libera la memoria. Quando il sistema non può fornire più memoria, restituisce NULL e visualizza la quantità massima utilizzabile finale di ram.

L'avvertenza è che il tuo sistema inizierà a scambiare pesantemente la memoria nelle fasi finali. A seconda della configurazione del sistema, il kernel potrebbe decidere di terminare alcuni processi. Uso incrementi di 100 MiB, quindi c'è un po' di respiro per alcune app e il sistema. Dovresti chiudere tutto ciò che non vuoi che vada in crash.

Detto ciò. Nel mio sistema in cui sto scrivendo questo non si è bloccato nulla. E il programma sopra riporta a malapena lo stesso di ulimit -a . La differenza è che ha effettivamente testato la memoria e per mezzo di memset() ha confermato che la memoria è stata fornita e utilizzata.

Per il confronto su una macchina virtuale Ubuntu 10.04x86 con 256 MiB di RAM e 400 MiB di swap, il rapporto ulimit era memory size (kbytes, -m) unlimited e il mio programmino riportava 524.288.000 byte, che è all'incirca la somma di ram e swap, escludendo la ram utilizzata da altri software e dal kernel.

Modifica:come ha scritto Adam Zalcman, ulimit -m non è più onorato sui kernel Linux 2.6 e successivi più recenti, quindi mi correggo. Ma ulimit -v è onorato. Per risultati pratici dovresti sostituire -m con -v e cercare virtual memory (kbytes, -v) 4515440 . Sembra un puro caso che la mia casella suse avesse il valore -m coincidente con quanto riportato dalla mia piccola utility. Dovresti ricordare che questa è la memoria virtuale assegnata dal kernel, se la ram fisica è insufficiente ci vorrà spazio di swap per compensare.

Se vuoi sapere quanta RAM fisica è disponibile senza disturbare alcun processo o il sistema, puoi usare

long total_available_ram =sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) ;

questo escluderà la cache e la memoria buffer, quindi questo numero può essere molto più piccolo della memoria effettivamente disponibile. Le cache del sistema operativo possono essere abbastanza grandi e la loro eliminazione può fornire la memoria aggiuntiva necessaria, ma viene gestita dal kernel.


La gestione dell'heap e della memoria è una funzione fornita dalla tua libreria C (probabilmente glibc). Mantiene l'heap e ti restituisce blocchi di memoria ogni volta che esegui un malloc() . Non conosce il limite della dimensione dell'heap:ogni volta che richiedi più memoria di quella disponibile sull'heap, va semplicemente e ne chiede di più al kernel (usando sbrk() o mmap() ).

Per impostazione predefinita, il kernel ti darà quasi sempre più memoria quando richiesto. Ciò significa che malloc() restituirà sempre un indirizzo valido. È solo quando fai riferimento a una pagina assegnata per la prima volta che il kernel si preoccuperà effettivamente di trovare una pagina per te. Se scopre che non può dartene uno, esegue un killer OOM che secondo una certa misura chiamato cattiveria (che include le dimensioni della memoria virtuale del tuo processo e dei suoi figli, il buon livello, il tempo di esecuzione complessivo ecc.) seleziona una vittima e le invia un SIGTERM . Questa tecnica di gestione della memoria è chiamata overcommit ed è usata dal kernel quando /proc/sys/vm/overcommit_memory è 0 o 1. Vedi overcommit-accounting nella documentazione del kernel per i dettagli.

Scrivendo 2 in /proc/sys/vm/overcommit_memory puoi disabilitare l'overcommit. Se lo fai, il kernel verificherà effettivamente se ha memoria prima di prometterlo. Ciò risulterà in malloc() restituisce NULL se non è più disponibile memoria.

Puoi anche impostare un limite sulla memoria virtuale che un processo può allocare con setrlimit() e RLIMIT_AS o con il ulimit -v comando. Indipendentemente dall'impostazione di overcommit descritta sopra, se il processo tenta di allocare più memoria rispetto al limite, il kernel lo rifiuterà e malloc() restituirà NULL. Nota che nel kernel Linux moderno (inclusa l'intera serie 2.6.x) il limite sulla dimensione residente (setrlimit() con RLIMIT_RSS o ulimit -m comando) è inefficace.

La sessione seguente è stata eseguita sul kernel 2.6.32 con 4 GB di RAM e 8 GB di swap.

$ cat bigmem.c
#include <stdlib.h>
#include <stdio.h>

int main() {
  int i = 0;
  for (; i < 13*1024; i++) {
    void* p = malloc(1024*1024);
    if (p == NULL) {
      fprintf(stderr, "malloc() returned NULL on %dth request\n", i);
      return 1;
    }
  }
  printf("Allocated it all\n");
  return 0;
}
$ cc -o bigmem bigmem.c
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ sudo bash -c "echo 2 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
2
$ ./bigmem
malloc() returned NULL on 8519th request
$ sudo bash -c "echo 0 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ ulimit -v $(( 1024*1024 ))
$ ./bigmem
malloc() returned NULL on 1026th request
$

Nell'esempio sopra non potrebbero mai verificarsi swapping o OOM kill, ma questo cambierebbe in modo significativo se il processo provasse effettivamente a toccare tutta la memoria allocata.

Per rispondere direttamente alla tua domanda:a meno che tu non abbia un limite di memoria virtuale esplicitamente impostato con ulimit -v comando, non esiste alcun limite di dimensione dell'heap diverso dalle risorse fisiche della macchina o dal limite logico dello spazio degli indirizzi (rilevante nei sistemi a 32 bit). Il tuo glibc continuerà ad allocare memoria sull'heap e ne richiederà sempre di più dal kernel man mano che il tuo heap cresce. Alla fine potresti finire per scambiare male se tutta la memoria fisica è esaurita. Una volta esaurito lo spazio di swap, un processo casuale verrà ucciso dall'OOM killer del kernel.

Si noti tuttavia che l'allocazione della memoria potrebbe non riuscire per molte più ragioni oltre alla mancanza di memoria libera, alla frammentazione o al raggiungimento di un limite configurato. Il sbrk() e mmap() le chiamate utilizzate dall'allocatore di glib hanno i propri errori, ad es. l'interruzione del programma ha raggiunto un altro indirizzo già allocato (es. memoria condivisa o una pagina precedentemente mappata con mmap() ) o è stato superato il numero massimo di mappature di memoria del processo.


Linux
  1. Come controllare l'utilizzo della memoria del processo con il comando pmap di Linux

  2. Come controllare la dimensione della RAM nella riga di comando di Linux in Gb

  3. Come verificare se un sistema Linux è a 32 o 64 bit

  4. come controllare la dimensione dell'heap allocata per jvm da linux

  5. Come viene riportato l'utilizzo della memoria in Linux?

Come controllare la versione di Linux

Come controllare (scansionare) le porte aperte in Linux

Come controllare l'utilizzo della memoria in Linux

Come controllare/riparare il file system Linux all'avvio

Come controllare il carico del server nel sistema Linux

Come tracciare e tracciare un processo Linux