How to re-load all running applications from swap space into RAM?

19,684

Solution 1

If you really have enough RAM available again you can use this sequence (as root):

$ swapoff -a
$ swapon -a

(to force the explicit swap-in of all your applications)

(assuming that you are using linux)

Solution 2

The following quick-and-dirty python script dumps the memory of a process to stdout. This has the side effect of loading any swapped out page or mapped file. Call it as cat_proc_mem 123 456 789 where the arguments are process IDs.

This script is completely specific to Linux. It may be adaptable to other systems with a similar /proc structure (Solaris?), but forget about running it on e.g. *BSD. Even on Linux, you may need to change the definition of c_pid_t and the values of PTRACE_ATTACH and PTRACE_DETACH. This is a proof-of-principle script, not meant as an example of good programming practices. Use at your own risk.

Linux makes the memory of a process available as /proc/$pid/mem. Only certain address ranges are readable. These ranges can be found by reading the memory mapping information from the text file /proc/$pid/maps. The pseudo-file /proc/$pid/mem cannot be read by all processes that have the permission to read it: the reader process must have called 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)

See also more information on /proc/$pid/mem.

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

Solution 3

Just for completeness, GDB can dump process image. I didn't check that it unswaps it, but it has to---there's no other way to read the whole process memory:
gdb -p $mypid
followed by
(gdb) gcore /tmp/myprocess-core
Saved corefile /tmp/myprocess-core

Share:
19,684

Related videos on Youtube

profy
Author by

profy

Updated on September 17, 2022

Comments

  • profy
    profy over 1 year

    If my desktop run out of memory and swaps a lot then I free or kill the application wasting my RAM. But, after that, all my desktop/applications have been swapped and are horribly slow, do you know a way to "unswap" (reload from swap space into RAM) my desktop/applications?

    • Admin
      Admin over 10 years
      Rather than to unswap the entire system using swapon/swapoff (as the currently accepted answer suggests), you might want to unswap your display manager and all its children by dumping their process memories (which force unswapping). See also “How to force a swapped-out zsh process to swap in?” on stackoverflow.
  • Louis Gerbarg
    Louis Gerbarg over 13 years
    Even if you don't IIRC it will move as much data as possible. While it may damage cache & co. it is sometimes useful.
  • Juliano
    Juliano over 13 years
    Swap memory is, by definition, not cache. Dropping the caches is very unlikely to change anything in the swap. Also, it is preferable to use sysctl instead of directly writing over files in the proc filesystem. sysctl vm.drop_caches=X. Also, sysctl is easier to sudo.
  • xenoterracide
    xenoterracide over 13 years
    @julian virtual memory = ram + swap iirc. Both applications and caches use virtual memory. However I think that the op needs to clear everything but caches from swap, as I doubt those are really what's effecting him.
  • Juliano
    Juliano over 13 years
    @xenoterracide: caches only make sense in real, RAM memory. It is pointless to store cache in the swap, they are complete opposites. Swap is slow memory used when the system is short on physical RAM; cache is fast memory used when the system has plenty of unused physical RAM.
  • xenoterracide
    xenoterracide over 13 years
    @juliano yes I know, but I believe they are both stored using virtual memory, though it's possible that caches only get stored in RAM. honestly dropping the caches makes no sense here, imo.
  • Dan
    Dan over 8 years
    This is seriously one of the coolest things I've ever seen on stack exchange. Kudos for posting this! There are so many good nuggets to pull from this.
  • barteks2x
    barteks2x about 7 years
    Unformatunately I wasn't able to get this script working. With python 2 it shows error that the value r[0] is too big. On python 3 (after fixing a few minor issues) I get OSError: [Errno 5] Input/output error at chunk = mem_file.read(r[1] - r[0]) and the program I used it on hangs in both cases.
  • Gilles 'SO- stop being evil'
    Gilles 'SO- stop being evil' about 7 years
    @Barteks2x I'm sorry, I don't have the time right now to make this script error-proof. It does work for me, at least on machines that don't have too many security restrictions (the technique uses some debugging interfaces that are disabled on hardened setups). The program is suspended while it's being traced, send it a SIGCONT (kill -CONT 1234 where 1234 is the PID) to resume it.
  • hackerb9
    hackerb9 almost 7 years
    @Barteks2x: I've added some error checking here. This makes the script work even on IOErrors from /dev/dri/card0 and OverflowErrors from [vsyscall]. (It also prints out what the problem area was).
  • hackerb9
    hackerb9 almost 7 years
    gcore has no way to write to /dev/null, which is what you'd want if you were trying to force a process back into memory. However, you can do it in a single command like so: gdb --batch -p $pid -ex "gcore /dev/null" 2>/dev/null
  • Ian D. Allen
    Ian D. Allen over 2 years
    If you don't want to write Python to read all the process memory and force it to swap in, you can use a short gdb script to do the same thing. See the script I posted under “How to force a swapped-out zsh process to swap in?” on stackoverflow.