Deframmentazione RAM / OOM non riuscita


11

Questa domanda è piuttosto lunga, quindi farò le domande in alto e poi passerò attraverso il mio metodo di venire alle domande:

  1. (Basato su Busybox) rm non è stato eseguito perché non c'era abbastanza RAM contigua?
  2. In tal caso, esiste un metodo leggero per deframmentare il DMA - senza ricorrere al riavvio del sistema?
  3. In caso contrario, cosa l'ha causato? Come posso evitare che accada in futuro?

Dopo che il nostro sistema di test ha funzionato abbastanza intensamente negli ultimi giorni, ho telnetato nel sistema e controllato i risultati del test. Quando sono venuto per eliminare alcuni dati, il sistema ha restituito la riga di comando (come se il comando fosse stato eseguito correttamente). Quando sono venuto a controllare la directory per un altro set di risultati, ho visto che il file esisteva ancora (usando ls).

Dopo questo, ho notato che sempre più dei miei comandi shell non funzionavano come previsto.

Inizierò con un output di dmesg dopo che rm non è stato eseguito correttamente:

Allocazione della lunghezza 61440 dal processo 6821 (rm) non riuscita

DMA per CPU:

CPU 0: hi: 0, btch: 1 usd: 0

Active_anon: 0 active_file: 1 inactive_anon: 0 inactive_file: 0 instabile: 6 sporco: 0 riscrittura: 0 instabile: 0 libero: 821 lastra: 353 mappato: 0 pagetables: 0 rimbalzo: 0

DMA gratuito: 3284kB min: 360kB basso: 448kB alto: 540kB active_anon: 0kB inactive_anon: 0kB active_file: 4kB inactive_file: 0kB non rilevabile: 24kB presente: 8128kB pagine_scansionate: 0 all_unreclaimable? no

lowmem_reserve []: 0 0 0

DMA: 31 * 4 kB 47 * 8 kB 42 * 16 kB 64 * 32 kB 1 * 64 kB 0 * 128 kB 0 * 256 kB 0 * 512 kB 0 * 1024 kB 0 * 2048 kB 0 * 4096 kB = 3284 kB

14 pagine di pagecache totali

Impossibile allocare RAM per i dati di processo, errno 12

Inizialmente, pensavo di non essere in grado di eseguire il programma nella maggior parte della memoria contigua. Significa che il DMA era troppo frammentato e avrei dovuto trovare un modo per far deframmentare la memoria del sistema.

Quindi ho fatto un rapido controllo di matematica / sanità mentale e mi sono reso conto che il programma avrebbe dovuto essere in grado di funzionare nell'unico slot di memoria contiguo da 64 kB. Rm richiedeva 61440 byte (60kB).

Ho fatto una buona "deframmentazione manuale" e riavviato il sistema. Quando ho riavviato il sistema ho prodotto / proc / buddyinfo:

Node 0, zone DMA 2 8 3 12 0 1 0 1 0 1 0

Che sospetto mappa per:

  • 2 x 4 kB
  • 8 x 8 kB
  • 3 x 16 kB
  • 12 x 32 kB
  • 1 x 128 kB
  • 1 x 512 kB

Ma se si somma il precedente elenco di valori, non corrisponde all'output di / proc / meminfo :

MemTotal:           6580 kB
MemFree:            3164 kB
Buffers:               0 kB
Cached:              728 kB
SwapCached:            0 kB
Active:              176 kB
Inactive:            524 kB
Active(anon):          0 kB
Inactive(anon):        0 kB
Active(file):        176 kB
Inactive(file):      524 kB`
Unevictable:           0 kB
Mlocked:               0 kB
MmapCopy:            844 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:             0 kB
Mapped:                0 kB
Slab:               1268 kB
SReclaimable:        196 kB
SUnreclaim:         1072 kB
PageTables:            0 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:        3288 kB
Committed_AS:          0 kB
VmallocTotal:          0 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB

Per ricapitolare, le mie domande sono:

  1. Rm non è stato eseguito perché non c'era abbastanza RAM contigua?
  2. In tal caso, esiste un metodo leggero per deframmentare il DMA - senza ricorrere al riavvio del sistema?
  3. In caso contrario, cosa l'ha causato? Come posso evitare che accada in futuro?

Sto usando XPort Pro (8 MB, Linux OS) di Lantronix con uClinux versione 2.6.30. La shell in uso è zitta.


Punto minore: hai lasciato fuori 1 x 2048 kB dal tuo elenco di blocchi di memoria. Se lo includi, la somma è 3192 kB che è molto vicino ai 3164 kB elencati in / proc / meminfo.
Alex Selby,

Risposte:


11

Sulla tua domanda 2 (deframmentare la memoria), citando da https://www.kernel.org/doc/Documentation/sysctl/vm.txt :

compact_memory

Disponibile solo quando è impostato CONFIG_COMPACTION. Quando 1 viene scritto nel file, tutte le zone vengono compattate in modo tale che la memoria libera sia disponibile in blocchi contigui ove possibile. Questo può essere importante, ad esempio, nell'allocazione di pagine enormi, sebbene i processi compattino direttamente la memoria, se necessario.

questo implica che il seguente comando (eseguito con i privilegi di root e se l'opzione del kernel sopra menzionata fosse abilitata)

echo 1 > /proc/sys/vm/compact_memory

dovrebbe dire al kernel di tentare di deframmentare la memoria il più possibile. Attenzione, ad esempio su alcune versioni di RHEL6, questo può causare l'arresto anomalo del kernel ...


1
Grazie per aver dedicato del tempo a tornare e commentare una vecchia domanda!
OldTinfoil

7

Ci è voluto un po 'di tempo, ma ho pensato di non rispondere prima di avere risposte a tutte e 3 le mie domande secondarie.

Prima di iniziare, però, menzionerò che il termine corretto quando si tratta di "frammentare" la memoria di lavoro si riferisce a "compattare" la memoria di lavoro.

1. Rm non è stato eseguito perché non c'era abbastanza RAM contigua?

Avevo ragione nelle mie conclusioni: rm non veniva eseguito perché la RAM contigua era insufficiente. Il sistema stava acquisendo RAM e frammentandola, rendendola così irriconoscibile.

2. In tal caso, esiste un metodo leggero per deframmentare il DMA - senza ricorrere al riavvio del sistema?

Si scopre che non c'è modo di compattare la memoria, a meno di riavviare il sistema incorporato. Nel caso di un sistema senza MMU, la prevenzione è il nome del gioco.

Una parte di me medita se è possibile hackerare il kernel Linux per emulare la MMU nel software. Immagino che se fosse possibile, qualcuno l'avrebbe già fatto. Non riesco a immaginare che sia un concetto completamente nuovo;)

3. Come posso impedire che ciò accada in futuro?

Per questo progetto, stavo usando cron per avviare manualmente il programma ogni volta che era necessario. Un modo molto migliore per farlo è quello di chiamare il programma all'avvio e quindi forzare il programma a dormire fino a quando non è necessario. In questo modo, la memoria non deve essere allocata ad ogni utilizzo. Riducendo così la frammentazione.

Sulla prima iterazione del progetto, abbiamo fatto affidamento sulle mie chiamate di script shell per eseguire funzioni critiche (come rm). Non abbiamo visto la necessità di reinventare la ruota se non ce ne fosse bisogno.

Tuttavia, consiglierei di evitare la shell ove possibile per un sistema senza MMU -

( Domanda , cosa succede se si esegue ls -la /path/to/directory/ | grep file-i-seek?)

( Risposta : avvia un nuovo sottoprocesso)

Se è necessario implementare alcune delle funzionalità di script della shell principale nel programma C, si consiglia di verificare il codice sorgente utilizzato in BusyBox . È probabile che utilizzerai C nel tuo sistema incorporato.


Grazie per aver dedicato del tempo a tornare e condividere i tuoi risultati.
Caleb,

3
[Mi rendo conto che questo è vecchio] Emulare un MMU è difficile ... Senza un MMU, ogni programma usa direttamente gli indirizzi fisici come appaiono sul bus di memoria. Potresti emularne uno, ma dovresti intercettare ogni accesso alla memoria (proprio come fa un MMU reale). Le prestazioni sarebbero terribili. In alternativa, puoi usare i puntatori indiretti (come faceva Mac OS Classic, chiamandoli "handle"), ma poi hai un'API completamente difficile e molto difficile di fronte alla prelazione (Mac OS Classic utilizzava il multitasking cooperativo) .
derobert,

Grazie per essere tornato e passare il tempo a scrivere quella risposta. Non sapevo che MacOS classico lo avesse fatto.
OldTinfoil
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.