Comment remplir 90% de la mémoire libre?

181

Je souhaite effectuer des tests avec peu de ressources et pour cela, je dois disposer de 90% de la mémoire libre.

Comment puis-je faire cela sur un *nixsystème?

Eduard Florinescu
la source
3
Est-ce que cela doit vraiment fonctionner sur n'importe quel système * nix?
un CVn
31
Au lieu de remplir simplement la mémoire, pourriez-vous créer une machine virtuelle (à l'aide de docker, ou vagant, ou quelque chose de similaire) disposant d'une quantité de mémoire limitée?
Abendigo
4
@abendigo Pour un QA, de nombreuses solutions présentées ici sont utiles: pour un système d'exploitation général sans plate-forme spécifique, les paramètres de démarrage de la machine virtuelle ou du noyau peuvent être utiles, mais pour un système embarqué dans lequel vous connaissez les spécifications de mémoire du système cible, optez pour le remplissage de la mémoire libre.
Eduard Florinescu
2
Ici, au cas où quelqu'un serait un peu choqué par la notation: meta.unix.stackexchange.com/questions/1513/… ?
goldilocks

Réponses:

157

stress-ng est un générateur de charge de travail qui simule les contraintes CPU / mem / io / hdd sur les systèmes POSIX. Cet appel devrait faire l'affaire sous Linux <3.14:

stress-ng --vm-bytes $(awk '/MemFree/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1

Pour Linux> = 3.14, vous pouvez MemAvailableplutôt utiliser l’ estimation de la mémoire disponible pour les nouveaux processus sans permutation:

stress-ng --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1

Adapter l' /proc/meminfoappel avec free(1)/ vm_stat(1)/ etc. si vous en avez besoin portable.

tkrennwa
la source
3
stress --vm-bytes $ (awk '/ MemFree / {printf "% d \ n", 2 $ * 0,097;}' </ proc / meminfo) k --vm-keep -m 10
Robert
1
La plus grande partie de MemFree est conservée par le système d’exploitation. J’ai donc utilisé MemAvailable. Cela m'a donné une utilisation de 92% sur Cent OS 7.stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.98;}' < /proc/meminfo)k --vm-keep -m 1
kujiy
bon à savoir, MemAvailable a été ajouté à "une estimation de la quantité de mémoire disponible pour le démarrage de nouvelles applications, sans permutation", voir git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/ … Et git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/…
tkrennwa
1
Juste comme une note ajoutée, à condition que les deux --vm 1 and --vm-keepsont très importants. Tout simplement --vm-bytesne fait rien et vous pourriez être induit en erreur en pensant que vous pouvez allouer autant de mémoire que vous avez besoin / envie. Je me suis laissé mordre par là jusqu'à ce que j'essaye de me vérifier en allouant 256G de mémoire. Ce n'est pas un défaut dans la réponse, il fournit les indicateurs corrects, juste un avertissement supplémentaire.
trafiquer
C'est pourquoi il y a -m 1. Selon la page de manuel stress, -m Nest l'abréviation de --vm N: spawn Nworkers spinning onmalloc()/free()
tkrennwa
93

Vous pouvez écrire un programme C dans malloc()la mémoire requise, puis l’utiliser mlock()pour éviter que la mémoire ne soit remplacée.

Ensuite, laissez le programme attendre la saisie au clavier, déverrouillez la mémoire, libérez-la et quittez.

Chris
la source
25
Il y a longtemps, j'ai dû tester un cas d'utilisation similaire. J'ai observé que tant que vous n'écrivez pas quelque chose dans cette mémoire, celle-ci ne sera pas réellement allouée (c'est-à-dire tant que la défaillance de la page survient). Je ne suis pas sûr que mlock () prenne soin de ça.
Poorna
2
Je suis d'accord avec @siri; Cependant, cela dépend de la variante UNIX que vous utilisez.
Anthony
2
Un peu d' inspiration pour le code. De plus, je pense que vous n'avez pas besoin de déverrouiller / libérer la mémoire . Le système d'exploitation le fera pour vous lorsque votre processus sera terminé.
Sébastien
9
Vous devez probablement écrire dans la mémoire, le noyau peut simplement surcharger si vous ne le faites que par malloc. Par exemple, si Linux est configuré pour, malloc retournera avec succès sans avoir réellement la mémoire libre, et n’allouera réellement la mémoire que lorsqu’elle est en cours d’écriture. Voir win.tue.nl/~aeb/linux/lk/lk-9.html
Bjarke Freund-Hansen
7
@Sebastian: callocrencontrera le même problème IIRC. Toute la mémoire indiquera simplement la même page zéro en lecture seule. Il ne sera réellement alloué que lorsque vous aurez essayé d'écrire dessus (ce qui ne fonctionnera pas puisqu'il est en lecture seule). La seule façon d'être vraiment sûr que je sache est de faire un memsettampon complet. Voir la réponse suivante pour plus d'informations stackoverflow.com/a/2688522/713554
Leo
45

Je suggérerais qu'exécuter une machine virtuelle avec une mémoire limitée et tester le logiciel serait un test plus efficace que d'essayer de remplir la mémoire sur la machine hôte.

Cette méthode présente également l’avantage que si la situation de mémoire insuffisante provoque des erreurs de MOO ailleurs et bloque tout le système d’exploitation, vous ne bloquez que la machine virtuelle que vous testez et non votre machine sur laquelle d’autres processus utiles pourraient s’exécuter.

De même, si vos tests ne nécessitent pas beaucoup de ressources processeur ou IO, vous pouvez simultanément exécuter des instances de tests sur une famille de machines virtuelles disposant de diverses tailles de mémoire.

David Spillett
la source
31

De ce commentaire HN: https://news.ycombinator.com/item?id=6695581

Il suffit de remplir / dev / shm via dd ou similaire.

swapoff -a
dd if=/dev/zero of=/dev/shm/fill bs=1k count=1024k
damio
la source
8
Tous les * nix n'ont pas / dev / shm. Une idée plus portable?
Tadeusz A. Kadłubowski
Si pvest installé, il est utile de voir le compte:dd if=/dev/zero bs=1024 |pv -b -B 1024 | dd of=/dev/shm/fill bs=1024
Otheus
1
Si vous voulez de la vitesse, cette méthode est le bon choix! Parce qu'il alloue la quantité de RAM souhaitée en quelques secondes. Ne relayez pas sur / dev / urandom, il utilisera 100% du processeur et prendra plusieurs minutes si votre RAM est importante. ENCORE, / dev / shm a une taille relative dans les distributions modernes Ubuntu / Debian, sa taille par défaut est de 50% de la RAM physique. Espérons que vous pourrez remonter / dev / shm ou peut-être créer un nouveau point de montage. Assurez-vous simplement qu'il a la taille réelle que vous souhaitez allouer.
develCuy
30
  1. exécutez linux;
  2. boot avec mem=nn[KMG]le paramètre de démarrage du noyau

(consultez linux / Documentation / kernel-parameters.txt pour plus de détails).

Anon
la source
24

Si vous avez des outils de base GNU ( sh, grep, yeset head) vous pouvez le faire:

yes | tr \\n x | head -c $BYTES | grep n
# Protip: use `head -c $((1024*1024*2))` to calculate 2MB easily

Cela fonctionne parce que grep charge la totalité de la ligne de données dans la RAM (je l’ai appris d’une manière plutôt malheureuse lors de la récupération d’une image de disque). La ligne, générée par yes, remplaçant les nouvelles lignes, sera infiniment longue, mais est limitée headà $BYTESoctets, donc grep chargera $ BYTES en mémoire. Grep lui-même utilise comme 100-200KB pour moi, vous devrez peut-être le soustraire pour un montant plus précis.

Si vous souhaitez également ajouter une contrainte de temps, vous pouvez le faire assez facilement bash(cela ne fonctionnera pas sh):

cat <(yes | tr \\n x | head -c $BYTES) <(sleep $NumberOfSeconds) | grep n

La <(command)chose semble être peu connue mais est souvent extrêmement utile, plus d'informations à ce sujet ici: http://tldp.org/LDP/abs/html/process-sub.html

Ensuite, pour l'utilisation de cat: catattendra que les entrées soient complètes jusqu'à la sortie, et en maintenant l'un des tuyaux ouverts, grep restera actif.

Si vous avez pvet souhaitez augmenter lentement l'utilisation de la RAM:

yes | tr \\n x | head -c $BYTES | pv -L $BYTESPERSEC | grep n

Par exemple:

yes | tr \\n x | head -c $((1024*1024*1024)) | pv -L $((1024*1024)) | grep n

Utilisera jusqu'à un gigaoctet à un taux de 1 Mo par seconde. En prime, pvvous montrera le taux d'utilisation actuel et l'utilisation totale jusqu'à présent. Bien sûr, cela peut également être fait avec les variantes précédentes:

yes | tr \\n x | head -c $BYTES | pv | grep n

Le simple fait d'insérer la | pv |pièce vous indiquera l'état actuel (débit et total, par défaut, je pense - sinon, voyez la page man (ual)).


Pourquoi une autre réponse? La réponse acceptée recommande d'installer un paquet (je parie qu'il y a une version pour chaque chipset sans avoir besoin d'un gestionnaire de paquet); la réponse la plus votée recommande de compiler un programme C (je n'avais pas de compilateur ni de chaîne d'outils à compiler pour votre plate-forme cible); la deuxième réponse la plus votée recommande d'exécuter l'application dans une VM (ouais, laissez-moi dd de la carte SD interne de ce téléphone via USB ou quelque chose du genre et créez une image de boîte virtuelle); la troisième suggère de modifier quelque chose dans la séquence d'amorçage qui ne remplit pas la RAM comme souhaité; le quatrième ne fonctionne que dans la mesure où le point de montage / dev / shm (1) existe et que (2) est grand (le remontage nécessite la racine); le cinquième combine plusieurs des éléments ci-dessus sans code exemple; la sixième est une excellente réponse mais je ne l’ai pas vue avant de proposer ma propre approche, alors j'ai pensé ajouter le mien, aussi parce que c'est plus court à retenir ou à taper si vous ne voyez pas que la ligne memblob est en réalité le noeud du problème; le septième encore ne répond pas à la question (utilise ulimit pour limiter un processus à la place); le huitième essaie de vous faire installer python; le neuvième pense que nous sommes tous très peu créatifs et finalement le dixième a écrit son propre programme C ++, ce qui pose le même problème que la réponse la plus votée.

Luc
la source
belle solution. Seul bémol, le code de sortie de la construction est 1 car grep ne trouve aucune correspondance. Aucune des solutions de stackoverflow.com/questions/6550484/… ne semble résoudre ce problème.
Holger Brandl
@ HolgerBrandl Bon point, je ne saurais pas comment résoudre ce problème. C'est la première fois que j'en entends parler set -e, alors je viens d'apprendre quelque chose :)
Luc
$ SECONDS ne semble pas être un bon choix car il s’agit d’une variable intégrée qui reflète le temps écoulé depuis le démarrage du shell. voir tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
Holger Brandl
@ HolgerBrandl Bonne prise, je ne le savais pas. Un peu cool de trouver un terminal ouvert depuis plus de 3 millions de secondes: D. J'ai mis à jour le post.
Luc
Technique cool! time yes | tr \\n x | head -c $((1024*1024*1024*10)) | grep n(utiliser 10 Go de mémoire) prend 1 minute 46 secondes. L'exécution du programme eatmemory de julman99 à l' adresse github.com/julman99/eatmemory prend 6 secondes. ... Et bien, plus le temps de téléchargement et de compilation, mais compilé sans problème ... et très rapidement ... sur ma machine RHEL6.4. Pourtant, j'aime cette solution. Pourquoi réinventer la roue?
Mike S
18

Je garde une fonction pour faire quelque chose de similaire dans mes fichiers de points. https://github.com/sagotsky/.dotfiles/blob/master/.functions#L248

function malloc() {
  if [[ $# -eq 0 || $1 -eq '-h' || $1 -lt 0 ]] ; then
    echo -e "usage: malloc N\n\nAllocate N mb, wait, then release it."
  else 
    N=$(free -m | grep Mem: | awk '{print int($2/10)}')
    if [[ $N -gt $1 ]] ;then 
      N=$1
    fi
    sh -c "MEMBLOB=\$(dd if=/dev/urandom bs=1MB count=$N) ; sleep 1"
  fi
}
valadil
la source
1
C’est la solution la plus intéressante à mon humble avis, puisqu’il n’a essentiellement besoin que de dd, toutes les autres tâches peuvent être traitées dans n’importe quel shell. Notez qu'il réclame en réalité deux fois plus de mémoire que les données générées par dd, du moins temporairement. Testé sur debian 9, tiret 0.5.8-2.4. Si vous utilisez bash pour exécuter la partie MEMBLOB, elle devient vraiment lente et utilise quatre fois plus que la quantité produite par dd.
P.Péter
16

Comment compter une simple solution python?

#!/usr/bin/env python

import sys
import time

if len(sys.argv) != 2:
    print "usage: fillmem <number-of-megabytes>"
    sys.exit()

count = int(sys.argv[1])

megabyte = (0,) * (1024 * 1024 / 8)

data = megabyte * count

while True:
    time.sleep(1)
swiftcoder
la source
7
Cela sera probablement rapidement échangé, ayant très peu d'impact sur la pression de la mémoire (à moins que vous ne remplissiez également tous les échanges, ce qui prend généralement un certain temps)
Joachim Sauer
1
Pourquoi un échange unix alors qu'il y a de la RAM disponible? C'est en fait un moyen plausible d'expulser le cache disque en cas de besoin.
Alexander Shcheblikin
@AlexanderShcheblikin Cette question ne concerne pas l'expulsion du cache disque (utile pour les tests de performance, mais pas pour les tests de ressources limitées).
Gilles
1
Cette solution permettait de gagner un gig ou deux lors de mes tests, bien que je n’ai pas essayé de stresser ma mémoire. Mais, @ JoachimSauer, vous pouvez définir sysctl vm.swappiness=0et définir de plus vm.min_free_kbytes sur un petit nombre, peut-être 1024. Je ne l'ai pas essayé, mais la documentation indique que c'est comme cela que vous contrôlez la rapidité de l'échange ... vous devriez le faire capable de le rendre assez lent, au point de provoquer une condition de MOO sur votre machine. Voir kernel.org/doc/Documentation/sysctl/vm.txt et kernel.org/doc/gorman/html/understand/understand005.html
Mike S Le
simplement un support pour 1 Go: python -c "x = (1 * 1024 * 1024 * 1024/8) * (0,); raw_input ()"
adrianlzt le
10

Que diriez-vous de ramfs s'il existe? Montez-le et copiez-le sur un gros fichier? S'il n'y a ni /dev/shmramfs - je suppose un petit programme en C qui effectue un gros malloc en fonction d'une valeur d'entrée? Vous devrez peut-être l'exécuter plusieurs fois à la fois sur un système 32 bits avec beaucoup de mémoire.

Nemo
la source
8

Si vous souhaitez tester un processus particulier avec une mémoire limitée, il peut être préférable ulimitde limiter la quantité de mémoire pouvant être allouée.

sj26
la source
2
En fait, cela ne fonctionne pas sur linux (aucun autre * nix). man setrlimit:RLIMIT_RSS Specifies the limit (in pages) of the process's resident set (the number of virtual pages resident in RAM). This limit only has effect in Linux 2.4.x, x < 30, and there only affects calls to madvise(2) specifying MADV_WILLNEED.
Patrick
4

Je pense que c’est le cas de poser la mauvaise question et de nuire à la santé mentale de personnes en compétition pour la réponse la plus créative. Si vous devez uniquement simuler les conditions de MOO, vous n'avez pas besoin de remplir la mémoire. Utilisez simplement un allocateur personnalisé et faites-le échouer après un certain nombre d'allocations. Cette approche semble fonctionner assez bien pour SQLite .

Craig Barnes
la source
3

J'ai écrit ce petit programme C ++ pour ça: https://github.com/rmetzger/dynamic-ballooner

L'avantage de cette implémentation est qu'elle vérifie périodiquement si elle doit libérer ou réallouer de la mémoire.

Robert Metzger
la source