Jak ponownie załadować wszystkie działające aplikacje z przestrzeni wymiany do pamięci RAM?

20

Jeśli na moim komputerze zabraknie pamięci i dużo się zamienia, to zwalniam lub zabijam aplikację marnującą pamięć RAM. Ale potem wszystkie moje pulpity / aplikacje zostały zamienione i są strasznie wolne, czy znasz sposób na „rozpakowanie” (przeładowanie z przestrzeni wymiany do pamięci RAM) na mój pulpit / aplikacje?

profy
źródło
Zamiast rozpakowywać cały system za pomocą swapon/ swapoff(jak sugeruje obecnie zaakceptowana odpowiedź), możesz chcieć rozpakować menedżera ekranu i wszystkie jego dzieci poprzez zrzucenie pamięci procesowych (co wymusza rozpakowanie). Zobacz także „Jak zmusić zamieniony proces zsh do zamiany?” Przy przepełnieniu stosu.
zrajm

Odpowiedzi:

16

Jeśli naprawdę masz wystarczająco dużo pamięci RAM, możesz użyć tej sekwencji (jako root):

$ swapoff -a
$ swapon -a

(aby wymusić jawną zamianę wszystkich aplikacji)

(przy założeniu, że używasz Linuksa)

maxschlepzig
źródło
Nawet jeśli nie IIRC, przeniesie jak najwięcej danych. Chociaż może uszkodzić pamięć podręczną i spółkę. czasem jest to przydatne.
Maciej Piechotka
19

Poniższy szybki i brudny skrypt Pythona zrzuca pamięć procesu na standardowe wyjście. Ma to efekt uboczny ładowania dowolnej zamienionej strony lub zmapowanego pliku. Nazwij to tak, jakby cat_proc_mem 123 456 789argumentami były identyfikatory procesów.

Ten skrypt jest całkowicie specyficzny dla Linuksa. Można go dostosować do innych systemów o podobnej /procstrukturze (Solaris?), Ale zapomnij o uruchomieniu go np. Na * BSD. Nawet w systemie Linux może być konieczna zmiana definicji c_pid_toraz wartości PTRACE_ATTACHi PTRACE_DETACH. Jest to skrypt sprawdzający zasadę, a nie jako przykład dobrych praktyk programistycznych. Używaj na własne ryzyko.

Linux udostępnia pamięć procesu jako /proc/$pid/mem. Tylko niektóre zakresy adresów są czytelne. Te zakresy można znaleźć, odczytując informacje o mapowaniu pamięci z pliku tekstowego /proc/$pid/maps. Pseudo-plik /proc/$pid/memnie może zostać odczytany przez wszystkie procesy, które mają uprawnienia do jego odczytu: proces czytający musiał go wywołać 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)

Zobacz także więcej informacji na temat/proc/$pid/mem .

unswap () {
  cat_proc_mem "$@" >/dev/null
}
Gilles „SO- przestań być zły”
źródło
2
To naprawdę jedna z najfajniejszych rzeczy, jakie widziałem na wymianie stosów. Wyrazy uznania za opublikowanie tego! Jest tyle dobrych samorodków, które można z tego wyciągnąć.
Dan
Niestety nie udało mi się uruchomić tego skryptu. W Pythonie 2 pokazuje błąd, że wartość r [0] jest za duża. Na Pythonie 3 (po naprawieniu kilku drobnych problemów) pojawia się błąd OSError: [Errno 5] Błąd wejścia / wyjścia w porcji = plik_ mem.read (r [1] - r [0]), a program, którego użyłem, zawiesza się w obu skrzynie
barteks2x
@ Barteks2x Przepraszam, nie mam teraz czasu, aby ten skrypt był odporny na błędy. Działa to dla mnie, przynajmniej na komputerach, które nie mają zbyt wielu ograniczeń bezpieczeństwa (technika wykorzystuje niektóre interfejsy debugowania, które są wyłączone w zaostrzonych konfiguracjach). Program jest zawieszony na czas śledzenia, wyślij mu SIGCONT ( kill -CONT 1234gdzie 1234 to PID), aby go wznowić.
Gilles „SO- przestań być zły”
@ Barteks2x: Dodałem trochę sprawdzanie błędów tutaj . To sprawia, że ​​skrypt działa nawet na IOErrors z / dev / dri / card0 i OverflowErrors z [vsyscall]. (Drukuje również obszar problemu).
hackerb9
6

Dla kompletności GDB może zrzucić obraz procesu. Nie sprawdziłem, czy to rozpakowuje, ale musi --- nie ma innego sposobu na odczytanie całej pamięci procesu:
gdb -p $mypid
a potem
(gdb) gcore /tmp/myprocess-core
Saved corefile /tmp/myprocess-core

przemek
źródło
3
gcore $pidjest również dostępny poza gdb (jako mały skrypt opakowujący)
Tobu
gcore nie ma sposobu na zapisanie do / dev / null, co byś chciał, gdybyś próbował zmusić proces z powrotem do pamięci. Można to jednak zrobić za pomocą jednego polecenia, takiego jak: gdb --batch -p $pid -ex "gcore /dev/null" 2>/dev/null
hackerb9
0

swapon / swapoff całkowicie wyczyści przestrzeń wymiany, ale możesz ją zwolnić również przez system plików / proc. Chcesz pierwszy:

# 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

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

Mark McKinstry
źródło
3
Pamięć wymiany z definicji nie jest pamięcią podręczną. Upuszczenie skrzynek raczej nie zmieni niczego w zamianie. Ponadto lepiej jest używać sysctl zamiast bezpośrednio zapisywać pliki w systemie plików proc. sysctl vm.drop_caches=X. Również sysctl jest łatwiejszy do sudo.
Juliano
@julian virtual memory = ram + swap iirc. Zarówno aplikacje, jak i pamięci podręczne używają pamięci wirtualnej. Myślę jednak, że operacja musi wyczyścić wszystko oprócz buforów z wymiany, ponieważ wątpię, czy to naprawdę na niego wpływa.
ksenoterrakid
@xenoterracide: pamięci podręczne mają sens tylko w prawdziwej pamięci RAM. Przechowywanie pamięci podręcznej w swapie nie ma sensu, są to kompletne przeciwieństwa. Zamiana to wolna pamięć używana, gdy w systemie brakuje fizycznej pamięci RAM ; pamięć podręczna to szybka pamięć używana, gdy system ma dużo nieużywanej fizycznej pamięci RAM .
Juliano
@juliano tak Wiem, ale wierzę, że oba są przechowywane przy użyciu pamięci wirtualnej, chociaż możliwe jest, że pamięci podręczne są przechowywane tylko w pamięci RAM. uczciwe upuszczanie skrzynek nie ma tutaj sensu, imo.
ksenoterracid