Comment recharger toutes les applications en cours d'exécution de l'espace d'échange dans la RAM?

20

Si mon bureau manque de mémoire et échange beaucoup, je libère ou tue l'application en gaspillant ma RAM. Mais, après cela, tous mes postes de travail / applications ont été échangés et sont horriblement lents, connaissez-vous un moyen de «décompresser» (recharger de l'espace de swap dans la RAM) mon bureau / applications?

profy
la source
Plutôt que de supprimer l'échange de l'ensemble du système à l'aide de swapon/ swapoff(comme le suggère la réponse actuellement acceptée), vous souhaiterez peut-être annuler l'échange de votre gestionnaire d'affichage et de tous ses enfants en vidant leurs mémoires de processus (ce qui force l'annulation de l'échange). Voir aussi «Comment forcer un processus zsh échangé à swap dedans?» Sur stackoverflow.
zrajm

Réponses:

16

Si vous avez vraiment suffisamment de RAM disponible, vous pouvez utiliser cette séquence (en tant que root):

$ swapoff -a
$ swapon -a

(pour forcer le swap-in explicite de toutes vos applications)

(en supposant que vous utilisez linux)

maxschlepzig
la source
Même si vous ne le faites pas, l'IIRC déplacera autant de données que possible. Bien que cela puisse endommager cache & co. c'est parfois utile.
Maciej Piechotka
19

Le script python rapide et sale suivant vide la mémoire d'un processus vers stdout. Cela a pour effet secondaire de charger une page ou un fichier mappé. Appelez-le comme cat_proc_mem 123 456 789où les arguments sont des ID de processus.

Ce script est complètement spécifique à Linux. Il peut être adaptable à d'autres systèmes avec une /procstructure similaire (Solaris?), Mais oubliez de l'exécuter par exemple sur * BSD. Même sous Linux, vous devrez peut-être modifier la définition c_pid_tet les valeurs de PTRACE_ATTACHet PTRACE_DETACH. Il s'agit d'un script de preuve de principe, non pas comme un exemple de bonnes pratiques de programmation. À utiliser à vos risques et périls.

Linux rend la mémoire d'un processus disponible en /proc/$pid/mem. Seules certaines plages d'adresses sont lisibles. Ces plages peuvent être trouvées en lisant les informations de mappage de mémoire dans le fichier texte /proc/$pid/maps. Le pseudo-fichier /proc/$pid/memne peut pas être lu par tous les processus autorisés à le lire: le processus lecteur doit avoir appelé 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)

Voir aussi plus d'informations sur/proc/$pid/mem .

unswap () {
  cat_proc_mem "$@" >/dev/null
}
Gilles 'SO- arrête d'être méchant'
la source
2
C'est sérieusement l'une des choses les plus cool que j'ai jamais vues sur l'échange de pile. Bravo pour avoir posté ça! Il y a tellement de bonnes pépites à tirer de cela.
Dan
Malheureusement, je n'ai pas réussi à faire fonctionner ce script. Avec python 2, il montre une erreur que la valeur r [0] est trop grande. Sur python 3 (après avoir corrigé quelques problèmes mineurs), j'obtiens OSError: [Errno 5] Erreur d'entrée / sortie à chunk = mem_file.read (r [1] - r [0]) et le programme sur lequel je l'ai utilisé se bloque dans les deux cas.
barteks2x
@ Barteks2x Je suis désolé, je n'ai pas le temps pour l'instant de rendre ce script à l'abri des erreurs. Cela fonctionne pour moi, au moins sur les machines qui n'ont pas trop de restrictions de sécurité (la technique utilise certaines interfaces de débogage qui sont désactivées sur les configurations renforcées). Le programme est suspendu pendant qu'il est tracé, envoyez-lui un SIGCONT ( kill -CONT 1234où 1234 est le PID) pour le reprendre.
Gilles 'SO- arrête d'être méchant'
@ Barteks2x: J'ai ajouté une vérification d'erreur ici . Cela fait que le script fonctionne même sur les IOErrors de / dev / dri / card0 et OverflowErrors de [vsyscall]. (Il imprime également quel était le problème).
hackerb9
6

Juste pour être complet, GDB peut vider l'image du processus. Je n'ai pas vérifié qu'il le déséchange, mais il doit --- il n'y a pas d'autre moyen de lire toute la mémoire du processus:
gdb -p $mypid
suivi de
(gdb) gcore /tmp/myprocess-core
Saved corefile /tmp/myprocess-core

przemek
la source
3
gcore $pidest également disponible en dehors de gdb (en tant que petit script wrapper)
Tobu
gcore n'a aucun moyen d'écrire dans / dev / null, ce que vous voudriez si vous essayiez de forcer un processus en mémoire. Cependant, vous pouvez le faire en une seule commande comme ceci: gdb --batch -p $pid -ex "gcore /dev/null" 2>/dev/null
hackerb9
0

swapon / swapoff effacera complètement votre espace de swap, mais vous pouvez également en libérer une partie via le système de fichiers / proc. Vous voulez le premier:

# 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

via http://linux-mm.org/Drop_Caches

Mark McKinstry
la source
3
La mémoire d'échange n'est pas, par définition, un cache. La suppression des caches est très peu susceptible de changer quoi que ce soit dans l'échange. De plus, il est préférable d'utiliser sysctl au lieu d'écrire directement sur des fichiers dans le système de fichiers proc. sysctl vm.drop_caches=X. De plus, sysctl est plus facile à sudo.
Juliano
@ mémoire virtuelle julienne = ram + swap iirc. Les applications et les caches utilisent la mémoire virtuelle. Cependant, je pense que l'op doit tout effacer sauf les caches du swap, car je doute que ce soit vraiment ce qui l'affecte.
xenoterracide
@xenoterracide: les caches n'ont de sens que dans la mémoire RAM réelle. Il est inutile de stocker le cache dans le swap, ce sont des opposés complets. L'échange est une mémoire lente utilisée lorsque le système manque de RAM physique ; le cache est une mémoire rapide utilisée lorsque le système a beaucoup de RAM physique inutilisée .
Juliano
@juliano oui je sais, mais je crois qu'ils sont tous deux stockés en utilisant la mémoire virtuelle, bien qu'il soit possible que les caches ne soient stockés qu'en RAM. Honnêtement, laisser tomber les caches n'a aucun sens ici, imo.
xenoterracide