Défragmentation de la défaillance RAM / OOM

11

Cette question est assez longue, donc je vais poser les questions en haut et ensuite passer par ma méthode pour arriver aux questions:

  1. (Basé sur Busybox) rm ne s'est-il pas exécuté parce qu'il n'y avait pas assez de RAM contiguë?
  2. Si oui, existe-t-il une méthode légère pour défragmenter le DMA - sans avoir recours à un redémarrage du système?
  3. Sinon, quelle en est la cause? Comment puis-je empêcher que cela se produise à l'avenir?

Après que notre système de test ait fonctionné assez intensivement au cours des derniers jours - j'ai telneté dans le système et vérifié les résultats du test. Lorsque je suis venu pour supprimer certaines données, le système a renvoyé la ligne de commande (comme si la commande s'était exécutée correctement). Quand je suis venu vérifier le répertoire pour un autre ensemble de résultats, j'ai vu que le fichier existait toujours (en utilisant ls).

Après cela, j'ai remarqué que de plus en plus de mes commandes shell ne fonctionnaient pas comme prévu.

Je vais commencer avec une sortie de dmesg après l'échec de l'exécution de rm:

Échec de l'allocation de la longueur 61440 à partir du processus 6821 (rm)

DMA par processeur:

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

Active_anon: 0 active_file: 1 inactive_anon: 0 inactive_file: 0 non prévisible: 6 sale: 0 écriture différée: 0 instable: 0 libre: 821 dalle: 353 mappé: 0 pagetables: 0 rebond: 0

Sans DMA: 3284 ko min: 360 ko bas: 448 ko haut: 540 ko active_anon: 0 ko inactif_anon: 0 ko fichier_actif: 4 ko fichier inactif: 0 ko non prévisible: 24 ko présent: 8128 ko pages numérisées: 0 tout_non récupérable? non

lowmem_reserve []: 0 0 0

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

14 pages de pagecache au total

Impossible d'allouer de la RAM pour les données de processus, errno 12

Au début, je pensais que j'étais incapable d'exécuter le programme dans la plus grande partie de la mémoire contiguë. Cela signifie que le DMA était trop fragmenté et que je devrais trouver un moyen d'obtenir que le système défragmente la mémoire.

Ensuite, j'ai fait une vérification rapide des mathématiques / de la santé mentale et j'ai réalisé que le programme aurait dû pouvoir s'exécuter dans le seul emplacement de mémoire contigu de 64 Ko. Rm demandait 61440 octets (60 Ko).

J'ai fait une bonne vieille "défragmentation manuelle" et j'ai redémarré le système. Lorsque j'ai redémarré le système, je produis / proc / buddyinfo:

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

Que je soupçonne de mapper:

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

Mais si l'on additionne la liste de valeurs ci-dessus, elle ne correspond pas à la sortie de / 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

Pour récapituler, mes questions sont les suivantes:

  1. Rm ne s'est-il pas exécuté parce qu'il n'y avait pas assez de RAM contiguë?
  2. Si oui, existe-t-il une méthode légère pour défragmenter le DMA - sans avoir recours à un redémarrage du système?
  3. Sinon, quelle en est la cause? Comment puis-je empêcher que cela se produise à l'avenir?

J'utilise XPort Pro de Lantronix (8 Mo, OS Linux) exécutant uClinux version 2.6.30. La coquille utilisée est silencieuse.

OldTinfoil
la source
Point mineur: vous avez omis 1 x 2048 ko de votre liste de morceaux de mémoire. Si vous incluez cela, la somme est de 3192 Ko, ce qui est très proche des 3164 Ko répertoriés dans / proc / meminfo.
Alex Selby

Réponses:

11

Sur votre question 2 (défragmenter la mémoire), en citant https://www.kernel.org/doc/Documentation/sysctl/vm.txt :

mémoire_compacte

Disponible uniquement lorsque CONFIG_COMPACTION est défini. Lorsque 1 est écrit dans le fichier, toutes les zones sont compactées de manière à ce que la mémoire libre soit disponible dans des blocs contigus lorsque cela est possible. Cela peut être important, par exemple, dans l'allocation de pages volumineuses, bien que les processus compactent également directement la mémoire si nécessaire.

cela implique que la commande suivante (exécutée avec les privilèges root et si l'option de noyau mentionnée ci-dessus a été activée)

echo 1 > /proc/sys/vm/compact_memory

devrait indiquer au noyau d'essayer de défragmenter la mémoire autant que possible. Attention par exemple sur certaines versions de RHEL6, cela peut planter le noyau ...

Andre Holzner
la source
1
Merci d'avoir pris le temps de revenir et de commenter une vieille question!
OldTinfoil
7

Cela a pris un peu de temps, mais j'ai pensé que je ne répondrais pas jusqu'à ce que j'aie des réponses à mes 3 sous-questions.

Avant de commencer cependant, je mentionnerai que le terme correct lorsqu'il s'agit de «dé-fragmenter» la mémoire de travail est appelé «compactage» de la mémoire de travail.

1. rm ne s'est-il pas exécuté parce qu'il n'y avait pas assez de RAM contiguë?

J'avais raison dans ma conclusion - rm ne s'est pas exécuté parce qu'il n'y avait pas suffisamment de RAM contiguë. Le système avait acquis de la RAM et l'avait fragmentée, la rendant ainsi irrécupérable.

2. Dans l'affirmative, existe-t-il une méthode légère de défragmentation du DMA - sans recourir à un redémarrage du système?

Il s'avère qu'il n'y a aucun moyen de compacter la mémoire, à moins de redémarrer le système embarqué. Dans le cas d'un système sans MMU, la prévention est le nom du jeu.

Une partie de moi se demande s'il est possible de pirater le noyau Linux pour émuler la MMU dans le logiciel. Je suppose que si c'était possible, quelqu'un l'aurait déjà fait. Je ne peux pas imaginer que c'est un concept entièrement nouveau;)

3. Comment puis-je empêcher que cela se produise à l'avenir?

Pour ce projet, j'utilisais cron pour lancer manuellement le programme chaque fois qu'il était nécessaire. Une bien meilleure façon de procéder consiste à appeler le programme au démarrage, puis à le forcer à s'endormir jusqu'à ce qu'il soit nécessaire. De cette façon, la mémoire n'a pas besoin d'être allouée à chaque utilisation. Réduisant ainsi la fragmentation.

Lors de la première itération du projet, nous nous sommes appuyés sur mes appels de script shell pour effectuer des fonctions critiques (telles que rm). Nous n'avons pas vu la nécessité de réinventer la roue si nous n'en avions pas besoin.

Cependant, je recommanderais d'éviter le shell autant que possible pour un système sans MMU -

( Question , que se passe-t-il si vous exécutez ls -la /path/to/directory/ | grep file-i-seek?)

( Réponse : il démarre un nouveau sous-processus)

Si vous devez implémenter certaines des fonctionnalités de base du script shell dans votre programme C, je vous recommande de vérifier le code source utilisé dans BusyBox . Il y a de fortes chances que vous utilisiez C dans votre système embarqué.

OldTinfoil
la source
Merci d'avoir pris le temps de revenir et de partager vos découvertes.
Caleb
3
[Je me rends compte que c'est vieux] Émuler une MMU est difficile ... Sans une MMU, chaque programme utilise directement les adresses physiques telles qu'elles apparaissent sur le bus mémoire. Vous pouvez en émuler un, mais vous devez intercepter tous les accès à la mémoire (comme le fait une MMU réelle). La performance serait terrible. Alternativement, vous pouvez utiliser des pointeurs indirects (comme Mac OS Classic, les appelant des "poignées"), mais vous avez alors une API complètement difficile, et très difficile face à la préemption (Mac OS Classic utilisait le multitâche coopératif) .
derobert
Merci d'être revenu et d'avoir pris le temps d'écrire cette réponse. Je ne savais pas que MacOS Classic avait fait ça.
OldTinfoil