Come ricaricare tutte le applicazioni in esecuzione dallo spazio di swap nella RAM?


20

Se il mio desktop esaurisce la memoria e si scambia molto, allora libero o uccido l'applicazione sprecando la mia RAM. Ma, dopo ciò, tutti i miei desktop / applicazioni sono stati scambiati e sono orribilmente lenti, conosci un modo per "annullare lo scambio" (ricaricare dallo spazio di scambio nella RAM) il mio desktop / applicazioni?


Invece di annullare la swap dell'intero sistema usando swapon/ swapoff(come suggerisce la risposta attualmente accettata), potresti voler annullare la swap del tuo display manager e di tutti i suoi figli scaricando le loro memorie di processo (che impongono lo swapping). Vedi anche "Come forzare un processo zsh scambiato fuori per scambiare?" Su StackOverflow.
zrajm,

Risposte:


16

Se hai davvero abbastanza RAM disponibile di nuovo puoi usare questa sequenza (come root):

$ swapoff -a
$ swapon -a

(per forzare lo scambio esplicito di tutte le tue applicazioni)

(supponendo che tu stia usando Linux)


Anche se non IIRC sposterà il maggior numero possibile di dati. Mentre può danneggiare cache & co. a volte è utile.
Maciej Piechotka,

19

Il seguente script Python rapido e sporco scarica la memoria di un processo su stdout. Ciò ha l'effetto collaterale di caricare qualsiasi pagina scambiata o file mappato. Chiamalo come cat_proc_mem 123 456 789dove gli argomenti sono ID di processo.

Questo script è completamente specifico per Linux. Può essere adattabile ad altri sistemi con una /procstruttura simile (Solaris?), Ma dimentica di eseguirlo su es. * BSD. Anche su Linux, potrebbe essere necessario modificare la definizione c_pid_te i valori di PTRACE_ATTACHe PTRACE_DETACH. Questo è uno script di prova di principio, non inteso come esempio di buone pratiche di programmazione. Utilizzare a proprio rischio.

Linux rende disponibile la memoria di un processo come /proc/$pid/mem. Sono leggibili solo determinati intervalli di indirizzi. Questi intervalli possono essere trovati leggendo le informazioni sulla mappatura della memoria dal file di testo /proc/$pid/maps. Lo pseudo-file /proc/$pid/memnon può essere letto da tutti i processi che hanno il permesso di leggerlo: il processo del lettore deve aver chiamato 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)

Vedi anche maggiori informazioni su/proc/$pid/mem .

unswap () {
  cat_proc_mem "$@" >/dev/null
}

2
Questa è davvero una delle cose più belle che abbia mai visto in cambio di stack. Complimenti per aver pubblicato questo! Ci sono così tante buone pepite da cui attingere.
Dan

In modo non ufficiale non sono riuscito a far funzionare questo script. Con python 2 mostra l'errore che il valore r [0] è troppo grande. Su python 3 (dopo aver risolto alcuni problemi minori) ottengo OSError: [Errno 5] Errore di input / output su chunk = mem_file.read (r [1] - r [0]) e il programma su cui l'ho usato si blocca in entrambi casi.
barteks2x

@ Barteks2x Mi dispiace, non ho tempo per rendere questo script a prova di errore. Funziona per me, almeno su macchine che non hanno troppe restrizioni di sicurezza (la tecnica utilizza alcune interfacce di debug che sono disabilitate su configurazioni rinforzate). Il programma viene sospeso mentre viene tracciato, inviandolo a SIGCONT ( kill -CONT 1234dove 1234 è il PID) per riprenderlo.
Gilles 'SO- smetti di essere malvagio' il

@ Barteks2x: ho aggiunto alcuni errori nel controllo qui . Questo fa funzionare lo script anche su IOErrors da / dev / dri / card0 e OverflowErrors da [vsyscall]. (Stampa anche quale fosse l'area problematica).
hackerb9,

6

Solo per completezza, GDB può scaricare l'immagine di processo. Non ho verificato che lo annullasse, ma deve --- non c'è altro modo di leggere l'intera memoria del processo:
gdb -p $mypid
seguito da
(gdb) gcore /tmp/myprocess-core
Saved corefile /tmp/myprocess-core


3
gcore $pidè disponibile anche al di fuori di gdb (come un piccolo script wrapper)
Tobu,

gcore non ha modo di scrivere su / dev / null, che è quello che vorresti se cercassi di forzare un processo a tornare in memoria. Tuttavia, puoi farlo in un solo comando in questo modo: gdb --batch -p $pid -ex "gcore /dev/null" 2>/dev/null
hackerb9

0

swapon / swapoff cancella completamente lo spazio di swap, ma è possibile liberarne anche tramite il file system / proc. Vuoi il primo:

# 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

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


3
La memoria di scambio non è, per definizione, cache. Far cadere le cache è molto improbabile che cambi qualcosa nello swap. Inoltre, è preferibile usare sysctl invece di scrivere direttamente sui file nel filesystem proc. sysctl vm.drop_caches=X. Inoltre, sysctl è più facile da sudo.
Juliano,

@julian virtual memory = ram + swap iirc. Sia le applicazioni che le cache utilizzano la memoria virtuale. Tuttavia, penso che l'operazione debba cancellare tutto tranne le cache dallo swap, poiché dubito che siano proprio quello che lo sta influenzando.
xenoterracide,

@xenoterracide: le cache hanno senso solo nella memoria RAM reale. È inutile archiviare la cache nello swap, sono opposti completi. Lo scambio è una memoria lenta utilizzata quando il sistema è a corto di RAM fisica ; la cache è una memoria veloce usata quando il sistema ha molta RAM fisica inutilizzata .
Juliano,

@juliano sì, lo so, ma credo che entrambi siano archiviati usando la memoria virtuale, anche se è possibile che le cache vengano archiviate solo nella RAM. cadere onestamente le cache non ha senso qui, imo.
xenoterracide,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.