¿Cómo llenar el 90% de la memoria libre?

181

Quiero hacer algunas pruebas de bajos recursos y para eso necesito tener el 90% de la memoria libre llena.

¿Cómo puedo hacer esto en un *nixsistema?

Eduard Florinescu
fuente
3
¿Realmente tiene que funcionar en cualquier sistema * nix?
un CVn
31
En lugar de solo llenar memoria, ¿podrías crear una VM (usando docker, vagabundo o algo similar) que tenga una cantidad limitada de memoria?
abendigo
44
@abendigo Para un control de calidad, muchas de las soluciones presentadas aquí son útiles: para un sistema operativo de propósito general sin una plataforma específica, los parámetros de arranque de VM o kernel podrían ser útiles, pero para un sistema embebido donde conozca la especificación de memoria del sistema objetivo ir para el llenado de la memoria libre.
Eduard Florinescu
2
En caso de que alguien más esté un poco sorprendido por la puntuación aquí: meta.unix.stackexchange.com/questions/1513/… ?
Ricitos de oro

Respuestas:

157

stress-ng es un generador de carga de trabajo que simula el estrés de cpu / mem / io / hdd en los sistemas POSIX. Esta llamada debería hacer el truco en Linux <3.14:

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

Para Linux> = 3.14, puede usar MemAvailableen su lugar para estimar la memoria disponible para nuevos procesos sin intercambiar:

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

Adapte la /proc/meminfollamada con free(1)/ vm_stat(1)/ etc. Si lo necesitas portátil.

tkrennwa
fuente
3
stress --vm-bytes $ (awk '/ MemFree / {printf "% d \ n", $ 2 * 0.097;}' </ proc / meminfo) k --vm-keep -m 10
Robert
1
El SO mantiene la mayor parte de MemFree, por lo que utilicé MemAvailable en su lugar. Esto me dio un 92% de uso en Cent OS 7.stress --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.98;}' < /proc/meminfo)k --vm-keep -m 1
kujiy
Es bueno saber que se agregó MemAvailable para "estimar cuánta memoria está disponible para iniciar nuevas aplicaciones, sin intercambiar", consulte git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/ … Y git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/…
tkrennwa
1
Solo como una nota adicional, proporcionar ambos --vm 1 and --vm-keepes muy importante. Simplemente --vm-bytesno hace nada y puede que lo engañen y piense que puede asignar tanta memoria como necesite / desee. Me mordió esto hasta que traté de comprobar mi cordura mediante la asignación de 256G de memoria. Esta no es una falla en la respuesta, proporciona los indicadores correctos, solo una precaución adicional.
incipiente
Por eso hay -m 1. De acuerdo con la página de manual de estrés, -m Nes la abreviatura de --vm N: los Ntrabajadores engendran girandomalloc()/free()
tkrennwa
92

Puede escribir un programa en C en malloc()la memoria requerida y luego usar mlock()para evitar que la memoria se intercambie.

Luego, simplemente deje que el programa espere la entrada del teclado y desbloquee la memoria, libere la memoria y salga.

Chris
fuente
25
Hace mucho tiempo tuve que probar un caso de uso similar. Observé que hasta que escriba algo en esa memoria, no se asignará realmente (es decir, hasta que ocurra un error de página). No estoy seguro de si mlock () se preocupa por eso.
Poorna
2
Estoy de acuerdo con @siri; sin embargo, depende de la variante UNIX que esté utilizando.
Anthony
2
Alguna inspiración para el código. Además, creo que no necesita desbloquear / liberar la memoria . El sistema operativo lo hará por usted cuando finalice su proceso.
Sebastian
99
Probablemente tengas que escribir en la memoria, el kernel podría comprometerse demasiado si solo lo mallocas. Si está configurado para, por ejemplo, Linux permitirá que malloc regrese con éxito sin tener realmente la memoria libre, y solo asignará la memoria cuando se esté escribiendo. Ver win.tue.nl/~aeb/linux/lk/lk-9.html
Bjarke Freund-Hansen
77
@Sebastian: callocse encontrará con el mismo problema IIRC. Toda la memoria solo apuntará a la misma página puesta a cero de solo lectura. En realidad, no se asignará hasta que intente escribir en él (lo que no funcionará ya que es de solo lectura). La única forma de estar realmente seguro de que lo sé es hacer una parte memsetdel búfer completo. Consulte la siguiente respuesta para obtener más información stackoverflow.com/a/2688522/713554
Leo
45

Sugeriría ejecutar una VM con memoria limitada y probar el software en eso sería una prueba más eficiente que tratar de llenar la memoria en la máquina host.

Ese método también tiene la ventaja de que si la situación de poca memoria causa errores OOM en otro lugar y bloquea todo el sistema operativo, solo bloquea la VM que está probando, no en su máquina, en la que podría tener otros procesos útiles ejecutándose.

Además, si sus pruebas no son intensivas en CPU o IO, puede ejecutar simultáneamente las pruebas en una familia de máquinas virtuales con una variedad de tamaños de memoria baja.

David Spillett
fuente
31

De este comentario de HN: https://news.ycombinator.com/item?id=6695581

Simplemente complete / dev / shm a través de dd o similar.

swapoff -a
dd if=/dev/zero of=/dev/shm/fill bs=1k count=1024k
Damio
fuente
8
No todos los * nixes tienen / dev / shm. ¿Alguna idea más portátil?
Tadeusz A. Kadłubowski
Si pvestá instalado, es dd if=/dev/zero bs=1024 |pv -b -B 1024 | dd of=/dev/shm/fill bs=1024
útil
1
Si quieres velocidad, ¡este método es la elección correcta! Porque asigna la cantidad deseada de RAM en cuestión de segundos. No retransmita en / dev / urandom, usará el 100% de la CPU y tomará varios minutos si su RAM es grande. AÚN, / dev / shm tiene un tamaño relativo en las distribuciones modernas de Ubuntu / Debian, tiene un tamaño que por defecto es del 50% de la RAM física. Esperemos que pueda volver a montar / dev / shm o tal vez crear un nuevo punto de montaje. Solo asegúrese de que tenga el tamaño real que desea asignar.
develCuy
30
  1. ejecuta linux;
  2. arranque con mem=nn[KMG]el parámetro de arranque del kernel

(mire en linux / Documentation / kernel-parameter.txt para más detalles).

Luego
fuente
24

Si dispone de herramientas básicas de GNU ( sh, grep, yesy head) se puede hacer esto:

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

Esto funciona porque grep carga toda la línea de datos en RAM (aprendí esto de una manera bastante desafortunada cuando grep una imagen de disco). La línea, generada por yes, reemplazando las nuevas líneas, será infinitamente larga, pero está limitada heada $BYTESbytes, por lo que grep cargará $ BYTES en la memoria. Grep en sí usa como 100-200KB para mí, es posible que deba restar eso para obtener una cantidad más precisa.

Si también desea agregar una restricción de tiempo, esto se puede hacer con bastante facilidad en bash(no funcionará sh):

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

La <(command)cosa parece ser poco conocida, pero a menudo es extremadamente útil, más información aquí: http://tldp.org/LDP/abs/html/process-sub.html

Luego, para el uso de cat: catesperará a que se completen las entradas hasta que salga, y al mantener abierta una de las tuberías, mantendrá vivo a grep.

Si tiene pvy desea aumentar lentamente el uso de RAM:

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

Por ejemplo:

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

Utilizará hasta un gigabyte a una velocidad de 1 MB por segundo. Como una ventaja adicional, pvle mostrará la tasa de uso actual y el uso total hasta el momento. Por supuesto, esto también se puede hacer con variantes anteriores:

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

Simplemente insertando la | pv |parte le mostrará el estado actual (rendimiento y total, por defecto, creo; de lo contrario, vea la página man (ual)).


¿Por qué otra respuesta? La respuesta aceptada recomienda instalar un paquete (apuesto a que hay una versión para cada conjunto de chips sin necesidad de un administrador de paquetes); la respuesta más votada recomienda compilar un programa C (no tenía un compilador o una cadena de herramientas instalada para compilar para su plataforma de destino); la segunda respuesta más votada recomienda ejecutar la aplicación en una máquina virtual (sí, permítanme dd la tarjeta sd interna de este teléfono a través de usb o algo así y crear una imagen de caja virtual); el tercero sugiere modificar algo en la secuencia de arranque que no llena la RAM como se desea; el cuarto solo funciona en la medida en que existe / dev / shm mountpoint (1) y (2) es grande (el montaje necesita root); el quinto combina muchos de los anteriores sin código de muestra; la sexta es una gran respuesta, pero no vi esta respuesta antes de proponer mi propio enfoque, así que pensé en agregar el mío, también porque es más corto de recordar o escribir si no ves que la línea de memblob es realmente el quid de la cuestión; el séptimo nuevamente no responde la pregunta (en su lugar usa ulimit para limitar un proceso); el octavo intenta que instales python; el noveno piensa que todos somos muy poco creativos y finalmente el décimo escribió su propio programa C ++ que causa el mismo problema que la respuesta más votada.

Luc
fuente
solución encantadora La única falla es que el código de salida de la construcción es 1 porque grep no encuentra una coincidencia. Ninguna de las soluciones de stackoverflow.com/questions/6550484/… parece solucionarlo.
Holger Brandl
@HolgerBrandl Buen punto, no sabría cómo solucionarlo. Esta es la primera vez que oí hablar set -e, así que aprendí algo :)
Luc
$ SECONDS no parece una buena opción ya que es una variable integrada que refleja el tiempo desde que se inició el shell. ver tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
Holger Brandl
@HolgerBrandl Buena captura, no lo sabía. Es genial encontrar una terminal que esté abierta por más de 3 millones de segundos actualmente: D. Actualicé la publicación.
Luc
Técnica genial! time yes | tr \\n x | head -c $((1024*1024*1024*10)) | grep n(use memoria de 10 GiB) toma 1 minuto 46 segundos. Ejecutar el programa eatmemory de julman99 en github.com/julman99/eatmemory toma 6 segundos. ... Bueno, más el tiempo de descarga y compilación, pero se compiló sin problemas ... y muy rápidamente ... en mi máquina RHEL6.4. Aún así, me gusta esta solución. ¿Por qué reinventar la rueda?
Mike S
18

Mantengo una función para hacer algo similar en mis archivos de puntos. 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
fuente
1
Esta es la mejor solución en mi humilde opinión, ya que esencialmente solo necesita dd para funcionar, todas las demás cosas se pueden solucionar en cualquier shell. Tenga en cuenta que en realidad reclama el doble de memoria que los datos que produce dd, al menos temporalmente. Probado en Debian 9, guión 0.5.8-2.4. Si usa bash para ejecutar la parte MEMBLOB, se vuelve realmente lento y usa cuatro veces la cantidad que produce dd.
P.Péter
16

¿Cómo abunda una solución simple de 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
fuente
77
Eso probablemente se cambiará rápidamente, teniendo muy poco impacto real en la presión de la memoria (a menos que complete todo el intercambio también, lo que generalmente llevará un tiempo)
Joachim Sauer
1
¿Por qué un intercambio de Unix mientras hay RAM disponible? Esta es realmente una forma plausible de desalojar el caché del disco cuando sea necesario.
Alexander Shcheblikin
@AlexanderShcheblikin Esta pregunta no se trata de desalojar la memoria caché del disco (que es útil para las pruebas de rendimiento pero no para las pruebas de bajos recursos).
Gilles
1
Esta solución funcionó para improvisar un concierto o dos en mis pruebas, aunque no traté de estresar mi memoria. Pero, @JoachimSauer, uno podría establecer sysctl vm.swappiness=0y, además, establecer vm.min_free_kbytes en un número pequeño, tal vez 1024. No lo he probado, pero los documentos dicen que así es como controlas la rapidez de intercambio ... deberías ser capaz de hacerlo bastante lento, hasta el punto de causar una condición OOM en su máquina. Ver kernel.org/doc/Documentation/sysctl/vm.txt y kernel.org/doc/gorman/html/understand/understand005.html
Mike S
simplemente un liner para 1GB: python -c "x = (1 * 1024 * 1024 * 1024/8) * (0,); raw_input ()"
adrianlzt
10

¿Qué tal ramfs si existe? ¿Montarlo y copiar sobre un archivo grande? Si no /dev/shmhay ramfs y no hay ramfs, ¿supongo que un pequeño programa en C que hace un malloc grande basado en algún valor de entrada? Puede que tenga que ejecutarlo varias veces a la vez en un sistema de 32 bits con mucha memoria.

nemo
fuente
8

Si desea probar un proceso particular con memoria limitada, es mejor que utilice ulimitpara restringir la cantidad de memoria asignable.

sj26
fuente
2
En realidad, esto no funciona en Linux (no sé sobre otros * nixes). 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

Creo que este es un caso de hacer la pregunta incorrecta y la cordura ahogada por las personas que compiten por la respuesta más creativa. Si solo necesita simular condiciones OOM, no necesita llenar memoria. Simplemente use un asignador personalizado y haga que falle después de un cierto número de asignaciones. Este enfoque parece funcionar lo suficientemente bien para SQLite .

Craig Barnes
fuente