Come posso limitare la quantità di memoria disponibile a un processo?


11

Sto sviluppando un programma in corso; occasionalmente finisce per allocare grandi quantità di memoria (>> 10G su una macchina con 8G di memoria fisica), causando la mancata risposta del sistema. Voglio limitare la quantità di memoria che il processo può allocare. Il solito modo in cui lo farei è:

ulimit -m 4000000 ; ./myprogram

... che dovrebbe uccidere il mio programma se tenta di utilizzare più di 4 GB di memoria.

Su OS X El Capitan questo sembra non avere alcun effetto; anche ulimit -m 1(limitando tutti i programmi a solo 1kB di memoria!) è inefficace.

Come posso impostare un limite superiore della memoria disponibile per un determinato processo?


Quando dici Il solito modo in cui lo farei , cosa intendi? Più specificamente, quando lo fai di solito? E quando lo fai, intendi in Mac OS X El Capitan o in un altro ambiente? Puoi fare un esempio di quando l'hai usato con successo? Fondamentalmente, sto solo cercando di chiarire se questo processo funziona normalmente per te, ma non funziona per questo particolare programma? O non funziona affatto per te ma pensi che dovrebbe?
Monomeeth

1
Con "il solito modo in cui lo farei", intendo il modo in cui lo farei su altri gusti di Unix. Noto che ho appena scoperto che ulimit -mnon funziona più su Linux (> 2.4.30), anche se ulimit -vfunziona ancora come previsto. (Ad esempio ulimit -m, ulimit -vsembra non avere alcun effetto su OS X.)
cpcallen,

Sembra che hai una perdita di memoria nel programma che stai scrivendo e devi fare una migliore raccolta dei rifiuti. Hai letto sulla gestione della memoria in go?
Todd Dabney,

1
No, non una perdita di memoria, solo una ricerca grafica di uno spazio di stato potenzialmente molto grande. Potrei aggiungere codice per interrompere la ricerca se le varie strutture interne diventano troppo grandi, ma mi aspettavo di essere in grado di fare la stessa cosa (impedire che la macchina venisse incastrata da input di grandi dimensioni) con una shell one-liner.
cpcallen,

Risposte:


1

Esistono due approcci per limitare l'utilizzo della memoria: Ex post facto e Preemptive. Vale a dire, puoi provare a uccidere il tuo programma dopo che è diventato troppo grande, oppure puoi programmarlo per non diventare troppo grande in primo luogo.

Se insisti sull'approccio ex post facto, puoi utilizzare il seguente script Bash. Questo script rileva innanzitutto la quantità di memoria (definita da "dimensione set residente") utilizzata dal processo con processid pid, filtra tutti i dati non numerici utilizzando grep e salva la quantità come variabile n. Lo script controlla quindi se n è maggiore della x specificata. In tal caso, il processo con processid pid viene interrotto.

Notare che:

  1. È necessario sostituire <pid>con l'id processo del programma.
  2. È necessario sostituire <x>con rss = "resident set size" (ovvero dimensione della memoria reale) che non si desidera superare.

n=$(ps -<pid> -o rss | grep '[0-9]') if [ $n -gt <x> ]; then kill -9 <pid>; fi

Se vuoi che funzioni ogni y secondi, includilo in un ciclo e digli di aspettare y secondi dopo ogni iterazione. Puoi anche scrivere un comando simile usando top. Il tuo punto di partenza sarebbe top -l 1|grep "<pid>"|awk '{print $10}'.

La risposta di @ kenorb mi ha aiutato con la mia sceneggiatura


Mentre credo che risponda alla domanda, nel lungo periodo credo che sia meglio progettare la programmazione per adottare un approccio preventivo usando l'allocazione manuale della memoria.

Innanzitutto, sei sicuro che l'utilizzo della memoria sia davvero un problema? La documentazione Go afferma:

L'allocatore di memoria Go riserva un'ampia area di memoria virtuale come arena per le allocazioni. Questa memoria virtuale è locale per il processo Go specifico; la prenotazione non priva altri processi di memoria.

Se pensi ancora di avere un problema, ti incoraggio a gestire manualmente la tua memoria come avviene nel linguaggio di programmazione C. Dato che go è scritto in C, sospettavo che ci sarebbero stati modi per accedere alla gestione / allocazioni della memoria C, e in effetti ci sono. Vedi questo repository github che,

consente di eseguire la gestione manuale della memoria tramite l'allocatore C standard per il proprio sistema. È un involucro sottile sopra malloc, calloc e privo di. Vedi man malloc per i dettagli su queste funzioni per il tuo sistema. Questa libreria utilizza cgo.

Il caso d'uso è indicato come:

perchè vorresti questo?

Quando un programma sta causando pressione della memoria o il sistema sta esaurendo la memoria, può essere utile controllare manualmente le allocazioni di memoria e le deallocazioni. Go può aiutarti a controllare le allocazioni ma non è possibile deallocare esplicitamente i dati non necessari.

Sembra una soluzione a lungo termine migliore.

Se vuoi saperne di più su C (compresa la gestione della memoria), il linguaggio di programmazione C è il riferimento standard.


Sono sicuro che l'utilizzo della memoria sia davvero un problema. Quando il programma è cresciuto inaspettatamente> 2 volte la dimensione della memoria fisica, la macchina è diventata quasi del tutto non reattiva a causa del thrashing della pagina. Ci sono voluti circa un'ora tra quando ho premuto ^ C e quando macOS ha ripreso a rispondere ai clic del mouse; nel frattempo l'unica prova che non era congelato era il rumore silenzioso del disco rigido che ticchettava rapidamente.
cpcallen,

Questa è probabilmente una soluzione ragionevole nella pratica, ma a differenza di ulimit su sistemi operativi UNIX (non Darwin) dipende dalla capacità di allocare memoria sufficiente in modo tempestivo per eseguire con successo il comando kill. Preferirei che il kernel imponesse limiti di dimensione del processo.
cpcallen,

@cpcallen facendo qualche ricerca sembra che "il parametro -m ulimit non abbia alcun effetto sui sistemi Linux con versioni del kernel più recenti della 2.4.30". Sembra che anche OSX abbia colto questa modifica. Prova l'opzione -v per limitare lo spazio degli indirizzi
Evan Rosica,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.