¿Cómo volver a cargar todas las aplicaciones en ejecución desde el espacio de intercambio a la RAM?

20

Si mi escritorio se queda sin memoria y se intercambia mucho, entonces libero o elimino la aplicación desperdiciando mi RAM. Pero, después de eso, todos mis escritorios / aplicaciones han sido intercambiados y son horriblemente lentos, ¿conoces una forma de "desenterrar" (recargar desde el espacio de intercambio a la RAM) mis escritorios / aplicaciones?

profano
fuente
En lugar de cancelar el intercambio de todo el sistema usando swapon/ swapoff(como sugiere la respuesta actualmente aceptada), es posible que desee cancelar el intercambio de su administrador de pantalla y todos sus elementos secundarios al volcar sus memorias de proceso (lo que fuerza el cambio). Consulte también "¿Cómo forzar el intercambio de un proceso zsh intercambiado?" En stackoverflow.
zrajm

Respuestas:

16

Si realmente tiene suficiente RAM disponible nuevamente, puede usar esta secuencia (como root):

$ swapoff -a
$ swapon -a

(para forzar el intercambio explícito de todas sus aplicaciones)

(suponiendo que está utilizando Linux)

maxschlepzig
fuente
Incluso si no tiene IIRC, moverá la mayor cantidad de datos posible. Si bien puede dañar cache & co. A veces es útil.
Maciej Piechotka
19

El siguiente script de Python rápido y sucio volca la memoria de un proceso en stdout. Esto tiene el efecto secundario de cargar cualquier página intercambiada o archivo asignado. Llámelo como cat_proc_mem 123 456 789donde los argumentos son ID de proceso.

Este script es completamente específico para Linux. Puede ser adaptable a otros sistemas con una /procestructura similar (Solaris?), Pero olvídate de ejecutarlo, por ejemplo, * BSD. Incluso en Linux, es posible que deba cambiar la definición c_pid_ty los valores de PTRACE_ATTACHy PTRACE_DETACH. Este es un script de prueba de principio, no como un ejemplo de buenas prácticas de programación. Úselo bajo su propio riesgo.

Linux hace que la memoria de un proceso esté disponible como /proc/$pid/mem. Solo ciertos rangos de direcciones son legibles. Estos rangos se pueden encontrar leyendo la información de asignación de memoria del archivo de texto /proc/$pid/maps. El pseudoarchivo /proc/$pid/memno puede ser leído por todos los procesos que tienen permiso para leerlo: el proceso del lector debe haber llamado ptrace(PTRACE_ATTACH, $pid).

#!/usr/bin/env python
import ctypes, re, sys

## Partial interface to ptrace(2), only for PTRACE_ATTACH and PTRACE_DETACH.
c_ptrace = ctypes.CDLL("libc.so.6").ptrace
c_pid_t = ctypes.c_int32 # This assumes pid_t is int32_t
c_ptrace.argtypes = [ctypes.c_int, c_pid_t, ctypes.c_void_p, ctypes.c_void_p]
def ptrace(attach, pid):
    op = ctypes.c_int(16 if attach else 17) #PTRACE_ATTACH or PTRACE_DETACH
    c_pid = c_pid_t(pid)
    null = ctypes.c_void_p()
    err = c_ptrace(op, c_pid, null, null)
    if err != 0: raise SysError, 'ptrace', err

## Parse a line in /proc/$pid/maps. Return the boundaries of the chunk
## the read permission character.
def maps_line_range(line):
    m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
    return [int(m.group(1), 16), int(m.group(2), 16), m.group(3)]

## Dump the readable chunks of memory mapped by a process
def cat_proc_mem(pid):
    ## Apparently we need to ptrace(PTRACE_ATTACH, $pid) to read /proc/$pid/mem
    ptrace(True, int(pid))
    ## Read the memory maps to see what address ranges are readable
    maps_file = open("/proc/" + pid + "/maps", 'r')
    ranges = map(maps_line_range, maps_file.readlines())
    maps_file.close()
    ## Read the readable mapped ranges
    mem_file = open("/proc/" + pid + "/mem", 'r', 0)
    for r in ranges:
        if r[2] == 'r':
            mem_file.seek(r[0])
            chunk = mem_file.read(r[1] - r[0])
            print chunk,
    mem_file.close()
    ## Cleanup
    ptrace(False, int(pid))

if __name__ == "__main__":
    for pid in sys.argv[1:]:
        cat_proc_mem(pid)

Ver también más información sobre/proc/$pid/mem .

unswap () {
  cat_proc_mem "$@" >/dev/null
}
Gilles 'SO- deja de ser malvado'
fuente
2
Esta es seriamente una de las mejores cosas que he visto en el intercambio de pila. ¡Felicitaciones por publicar esto! Hay muchas buenas pepitas para sacar de esto.
Dan
Desafortunadamente, no pude hacer funcionar este script. Con python 2 muestra un error de que el valor r [0] es demasiado grande. En python 3 (después de solucionar algunos problemas menores) me sale OSError: [Errno 5] Error de entrada / salida en chunk = mem_file.read (r [1] - r [0]) y el programa en el que lo utilicé se cuelga en ambos casos.
barteks2x
@ Barteks2x Lo siento, no tengo tiempo en este momento para hacer que este script sea a prueba de errores. A mí me funciona, al menos en máquinas que no tienen demasiadas restricciones de seguridad (la técnica utiliza algunas interfaces de depuración que están deshabilitadas en configuraciones reforzadas). El programa se suspende mientras se está rastreando, envíele un SIGCONT ( kill -CONT 1234donde 1234 es el PID) para reanudarlo.
Gilles 'SO- deja de ser malvado'
@ Barteks2x: agregué algunos errores al verificar aquí . Esto hace que el script funcione incluso en IOErrors de / dev / dri / card0 y OverflowErrors de [vsyscall]. (También imprime cuál era el área del problema).
hackerb9
6

Solo para completar, GDB puede volcar la imagen del proceso. No verifiqué que lo intercambia, pero tiene que hacerlo --- no hay otra forma de leer la memoria completa del proceso:
gdb -p $mypid
seguido de
(gdb) gcore /tmp/myprocess-core
Saved corefile /tmp/myprocess-core

przemek
fuente
3
gcore $pidtambién está disponible fuera de gdb (como un script de contenedor pequeño)
Tobu
gcore no tiene forma de escribir en / dev / null, que es lo que desearía si intentara forzar un proceso de nuevo en la memoria. Sin embargo, puede hacerlo con un solo comando de la siguiente manera: gdb --batch -p $pid -ex "gcore /dev/null" 2>/dev/null
hackerb9
0

swapon / swapoff borrará completamente su espacio de intercambio, pero también puede liberar parte del mismo a través del sistema de archivos / proc. Quieres el primero:

# To free pagecache
echo 1 > /proc/sys/vm/drop_caches

# To free dentries and inodes
echo 2 > /proc/sys/vm/drop_caches

# To free pagecache, dentries and inodes
echo 3 > /proc/sys/vm/drop_caches

a través de http://linux-mm.org/Drop_Caches

Mark McKinstry
fuente
3
La memoria de intercambio no es, por definición, caché. Dejar caer los cachés es muy poco probable que cambie algo en el intercambio. Además, es preferible usar sysctl en lugar de escribir directamente sobre archivos en el sistema de archivos proc. sysctl vm.drop_caches=X. Además, sysctl es más fácil de sudo.
Juliano
@julian virtual memory = ram + swap iirc. Tanto las aplicaciones como los cachés usan memoria virtual. Sin embargo, creo que la operación necesita borrar todo, excepto los cachés del intercambio, ya que dudo que realmente sean lo que lo está afectando.
xenoterracide
@xenoterracide: los cachés solo tienen sentido en memoria RAM real. No tiene sentido almacenar caché en el intercambio, son completamente opuestos. El intercambio es memoria lenta utilizada cuando el sistema tiene poca RAM física ; La memoria caché es memoria rápida utilizada cuando el sistema tiene mucha RAM física no utilizada .
Juliano
@juliano sí, lo sé, pero creo que ambos se almacenan utilizando memoria virtual, aunque es posible que los cachés solo se almacenen en la RAM. honestamente, dejar los cachés no tiene sentido aquí, imo.
xenoterracide