22

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?

1
  • 1
    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.
    – zrajm
    Dec 13, 2013 at 10:30

4 Answers 4

23

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
}
5
  • 3
    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.
    – Dan
    Nov 8, 2015 at 4:40
  • 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.
    – barteks2x
    Mar 21, 2017 at 13:35
  • @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. Mar 21, 2017 at 14:47
  • @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
    Jul 24, 2017 at 17:57
  • 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. Nov 2, 2021 at 7:30
16

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)

1
  • Even if you don't IIRC it will move as much data as possible. While it may damage cache & co. it is sometimes useful. Jan 21, 2011 at 22:32
7

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

2
  • 4
    gcore $pid is also available outside of gdb (as a small wrapper script)
    – Tobu
    Jan 15, 2014 at 12:36
  • 1
    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
    – hackerb9
    Jul 24, 2017 at 18:11
0

swapon/swapoff will completely clear your swap space, but you can free some of it via the /proc file system too. You want the first one:

# 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

4
  • 3
    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.
    – Juliano
    Jan 21, 2011 at 23:59
  • @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. Jan 22, 2011 at 8:17
  • @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.
    – Juliano
    Jan 22, 2011 at 12:49
  • 1
    @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. Jan 22, 2011 at 13:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .