macOS Activity Monitor – What is App Memory Calculated From?

activity-monitormacmacos

I'm trying to use Geektool to keep a running monitor on my system, and wanted to include proper memory usage in my stats. I'm using Activity Monitor as the basis of my memory monitoring, but I'm running into an issue.

I can find and accurately calculate wired memory using the following command:

vm_stat | grep wired | awk '{print $4*4096/1024/1024/1024"GB"}'

I can't seem to get an accurate calculation of app memory though. I've tried adding up different portions of the vm_stat command to show app memory, but it doesn't seem to ever add up.

I've also tried getting used memory by trying to figure up the used, but it always comes back with more memory usage than Activity Monitor reports. I've looked online, and all Apple's website says is that App memory is the memory used by apps and background processes, which isn't really useful.

Is there combination of vm_stat pages that will add up to the used memory or app memory so that I can correctly show my memory usage in my geeklet?

Best Answer

After some frustration, I believe I have the answer.

vm_stat is only part of the picture, we also need:

$ sysctl vm.page_pageable_internal_count

App Memory is then:

page_pageable_internal_count - Pages Purgable (from vm_stat)

This Python script gets all of vm_stat, bits of sysctl, prints out it all prettily. The last 6 lines give the same numbers as Activity Monitor.

#!/usr/bin/python

import sys
import subprocess
import re

f = 0.00000000093132257   # 1/(1024*1024*1024) Converts bytes to GB

# vm_stat (get all results)
vm = subprocess.Popen(['vm_stat'], stdout=subprocess.PIPE).communicate()[0]

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

# sysctl  (just get a couple of numbers)
sy = subprocess.Popen(['sysctl','vm.page_pageable_internal_count'], stdout=subprocess.PIPE).communicate()[0]
p1 = sy.find(':')
page_pageable_internal_count = float(sy[p1+1:50]) * 4096
sy = subprocess.Popen(['sysctl','vm.swapusage'], stdout=subprocess.PIPE).communicate()[0]
p1 = sy.find('used')
p2 = sy.find('M',p1)
swapUsed = float(sy[p1+7:p2])   # This is Mbytes

appMemory = page_pageable_internal_count - vmStats["Pages purgeable"] 

print 'Wired Memory:\t\t%9.3f GB' % ( vmStats["Pages wired down"] * f )
print 'Active Memory:\t\t%9.3f GB' % ( vmStats["Pages active"] * f )
print 'Inactive Memory:\t%9.3f GB' % ( vmStats["Pages inactive"] * f )
print 'Speculative:\t\t%9.3f GB' % ( vmStats["Pages speculative"] * f )
print 'Throttled:\t\t%9.3f GB' % ( vmStats["Pages throttled"] * f )
print 'Free Memory:\t\t%9.3f GB' % ( vmStats["Pages free"] * f )

print 'Compressor:\t\t%9.3f GB' % ( vmStats["Pages occupied by compressor"] * f )
print 'Total:\t\t\t%9.3f GB' % ( (vmStats["Pages free"] + vmStats["Pages wired down"] + vmStats["Pages active"] + vmStats["Pages inactive"] + vmStats["Pages speculative"] + vmStats["Pages throttled"] + vmStats["Pages occupied by compressor"]) * f )
print ''
print 'Compressed:\t\t%9.3f GB' % ( vmStats["Pages stored in compressor"] * f )
print 'Purgeable:\t\t%9.3f GB' % ( vmStats["Pages purgeable"] * f )
print 'File-backed:\t\t%9.3f GB' % ( vmStats["File-backed pages"] * f )
print 'Anonymous:\t\t%9.3f GB' % ( vmStats["Anonymous pages"] * f )
print ''
print 'Pageable Internal:\t%9.3f GB' % (page_pageable_internal_count * f) 
print ''

print 'App Memory:\t\t%9.3f GB' % ( appMemory * f )
print 'Wired Memory:\t\t%9.3f GB' % ( vmStats["Pages wired down"] * f )
print 'Compressor:\t\t%9.3f GB  %9.3f MB' % ( vmStats["Pages occupied by compressor"] * f ,vmStats["Pages occupied by compressor"] * 1/(1024*1024) )
print 'Memory Used:\t\t%9.3f GB' % ( (appMemory + vmStats["Pages wired down"] + vmStats["Pages occupied by compressor"] ) * f )
print 'Cached Files:\t\t%9.3f GB' % ( (vmStats["File-backed pages"] + vmStats["Pages purgeable"]) * f )
print 'Swap Used:\t\t%9.3f GB  %9.3f MB' % ( swapUsed * 0.0009765625, swapUsed )

sys.exit(0);

The strange fudge factors are because a MB is 1024*1024 and a GB is 1024*1024*1024. A GB is not 1000 times a MB!

I have had most of this script for some time. The final piece of the puzzle was derived from https://stackoverflow.com/questions/31469355/how-to-calculate-app-and-cache-memory-like-activity-monitor-in-objective-c-in-ma