Automatically reclaim memory from leaky programs

Apr 11, '12 07:30:00AM

Contributed by: desepticon

Sometimes applications have a nasty habit of claiming a lot of memory and never releasing it back to the system. Over time, this can cause affect performance. Most of the time, this can simply be fixed by quitting and restarting the offending program, but I wanted to find a more elegant solution.

After searching the Internet, I found few scripts that I could tweak to achieve what I wanted. Heres what I came up with. The first script is a python script I found at StackExchange by user drfrogsplat that gets information about system memory. The second is a bash script I wrote that runs the purge command if you have over a certain amount of inactive memory, in my case 500MB (probably overkill). Note that I think you need developer tools installed to use the purge command. There's probably an easier way to do this with vm_stat directly but I'm not good enough at awk/grep/sed to it figure out.

The bash script can be attached to a launchd plist to run automatically at certain intervals or whenever you want. I seems to work pretty well for me.

#!/usr/bin/python

import subprocess
import re

# Get process info
ps = subprocess.Popen(['ps', '-caxm', '-orss,comm'], stdout=subprocess.PIPE).communicate()[0]
vm = subprocess.Popen(['vm_stat'], stdout=subprocess.PIPE).communicate()[0]

# Iterate processes
processLines = ps.split('\n')
sep = re.compile('[\s]+')
rssTotal = 0 # kB
for row in range(1,len(processLines)):
   rowText = processLines[row].strip()
   rowElements = sep.split(rowText)
   try:
       rss = float(rowElements[0]) * 1024
   except:
       rss = 0 # ignore...
   rssTotal += rss

# Process vm_stat
vmLines = vm.split('\n')
sep = re.compile(':[\s]+')
vmStats = {}
for row in range(1,len(vmLines)-2):
   rowText = vmLines[row].strip()
   rowElements = sep.split(rowText)
   vmStats[(rowElements[0])] = int(rowElements[1].strip('\.')) * 4096

print 'Wired Memory:\t\t%d MB' % ( vmStats["Pages wired down"]/1024/1024 )
print 'Active Memory:\t\t%d MB' % ( vmStats["Pages active"]/1024/1024 )
print 'Inactive Memory:\t%d MB' % ( vmStats["Pages inactive"]/1024/1024 )
print 'Free Memory:\t\t%d MB' % ( vmStats["Pages free"]/1024/1024 )
print 'Real Mem Total (ps):\t%.3f MB' % ( rssTotal/1024/1024 )

==============================================================
==============================================================

#!/bin/bash

MM=`/Path/to/python/script.py | awk '/Inactive/ {print $3}'`

echo "Testing status of inactive free memory..."

if [ "$MM" -gt "500" ]; then
    echo "You have too much inactive free memory." $MM"MB Releasing now..."
    purge
    exit 0
else
    echo "Memory ammount" $MM"MB does not meet purge threshold."
    exit 0
fi
[kirkmc adds: I'm guessing that this will be controversial. There seem to be dozens of apps on the Mac App Store that free up memory, and I'm not convinced that this is necessary. The only time I would see this as being essential is if that inactive memory is leading to more paging. Lately, I've been amazed at how little paging my Mac mini does; with 8 GB RAM, it rarely uses more than one swap file, and this with an uptime of several days.

I think that, in most cases, if you encounter an issue with memory, it's just as simple to use the purge command in Terminal. And, yes, I do see certain applications and processes taking up a lot of memory, notably iTunes and WebProcess. But note that the purge command doesn't free up all inactive memory anyway.

And, can someone confirm that Xcode is needed to have the purge command? Mine is in /usr/bin, and I don't think Xcode installs anything there, at least any more, now that it gets put in /Applications.]

Comments (36)


Mac OS X Hints
http://hints.macworld.com/article.php?story=20120410153721860