2

By "accurately describes the amount of used memory", I mean does it report (or can it be calculated) the same amount of memory use as described in Activity Monitor?

Activity monitor memory use: 14.20 gb

My intent is to find a method to programmatically access the amount of used physical memory in the system. In .NET Core 3.1 on Mac, this is impossible. My next option is to query a command line tool. My concern is that the figures reported below do not total up to 14.20 GB of used memory as expected in the above screenshot. This is why I claim they are inaccurate.

Below is what I've tried so far and why this is not a duplicate question. All commands were ran a second apart from each other after the above screenshot was taken.

Wired Memory:       5247 MB
Active Memory:      4170 MB
Inactive Memory:    3813 MB
Free Memory:        609 MB
Real Mem Total (ps):    11226.922 MB
  • top's "PhysMem" field claims that I'm using 15 GB on my system is in use. This is somewhat close, but it is has very rough rounding and sometimes rounds up to 16 GB in use.
PhysMem: 15G used (5269M wired), 960M unused.
  • How to calculate used memory on Mac OS by command line? The only answer describes vm_stat which is inaccurate and does not properly answer the question. I've read from around the web that to get the amount of used memory, you must sum "Active", "Inactive", and "Wired down" rows, then multiply it by page size. On this Catalina machine, this comes up to 13.8 GB (output below). Still kind of close, but this math is off by more than a GB on another Catalina machine.
Mach Virtual Memory Statistics: (page size of 4096 bytes)
Pages free:                              161443.
Pages active:                           1065326.
Pages inactive:                          974107.
Pages speculative:                        89929.
Pages throttled:                              0.
Pages wired down:                       1343201.
Pages purgeable:                          18630.
"Translation faults":                2149730807.
Pages copy-on-write:                  123210957.
Pages zero filled:                    965651547.
Pages reactivated:                    129523087.
Pages purged:                           3285194.
File-backed pages:                       292639.
Anonymous pages:                        1836723.
Pages stored in compressor:             3394212.
Pages occupied by compressor:            559818.
Decompressions:                       166263782.
Compressions:                         206698757.
Pageins:                              358184714.
Pageouts:                              10064704.
Swapins:                              123517427.
Swapouts:                             126184348.
  • memory_pressure doesn't seem to provide any accurate information related to memory usage. "System-wide memory free percentage" claims to be 54%, but 14.2 / 16 GB are in use.
The system has 2147483648 (524288 pages with a page size of 4096).

Stats:
Pages free: 162828
Pages purgeable: 16659
Pages purged: 3285194

Swap I/O:
Swapins: 123517427
Swapouts: 126184348

Page Q counts:
Pages active: 1062737
Pages inactive: 972247
Pages speculative: 89910
Pages throttled: 0
Pages wired down: 1346397

Compressor Stats:
Pages used by compressor: 559818
Pages decompressed: 166263778
Pages compressed: 206698757

File I/O:
Pageins: 358184697
Pageouts: 10064704

System-wide memory free percentage: 54%
9
  • Can you please run all the tests on the same machine (and basically at the same time) so different figures become comparable? Right now it‘s not clear what kind of gap you see.
    – nohillside
    Jul 7 at 17:10
  • 1
    @nohillside Thanks for the suggestion. I updated the original post with comparable figures. Jul 7 at 17:35
  • 1
    Superb research. I’m not sure I get what you’re trying to do or how “used” isn’t accurate. The figures reported are all highly precise and accurate, so I don’t know what problem you’re trying to solve where this information isn’t helpful.
    – bmike
    Jul 7 at 17:42
  • 1
    @bmike I want a way to programmatically access the amount of physical memory currently being used by the system. In .NET Core 3.1 on Mac, this isn't possible. The next solution (which is what this post concerns) is to try querying a command line tool that can do the job instead. The discrepancy between the numbers I'm seeing and what Activity Monitor reports is concerning and why I claim they are "inaccurate". I'll update my original post to make my intent more clear. Jul 7 at 18:22
  • 2
    One possible source of confusion is Gigabytes (1 GB =1000^3 bytes) vs Gibibytes (1 GiB =1024^3 bytes =~ 1.074 GB). Is it possible some of your numbers are in one of these, and some are in the other? Jul 7 at 19:25
4

The strict (rather trite) answer to the question is that the amount of memory being used is equal the amount physical memory. But let's be more helpful and get some answers as to how that physical memory is being used.

Just to complicate things there are at least two ways sets of numbers which add up to the physical memory:

  • "Traditional" unix style with wired, active, inactive, free, etc. with additions for compressed memory.
  • "Activity Monitor" memory which introduces App Memory.

The numbers we need can be extracted from the results of these commands:

  • vm_stat which gives us most of what we need,
  • selected numbers from sysctl, and
  • memory_pressure from which I use just one number.

There is overlap between the results of these commands and the memory_pressure rather perversely presents the inverse of Activity Monitor's pressure.

Memory Pressure is just a number which provides a simple way of indicating memory load. It can be calculated from vm_stat results or just taken from memory pressure. We should not worry too much about its physical interpretation - it just an indicative number.

I apologise upfront that I use a python script to collect the data and present it in a digestible format. First the results.

On my 8GB MacBook, right now I get this:

Traditional memory:
Wired Memory:           2.174 GB
Active Memory:          2.428 GB
Inactive Memory:        2.359 GB
Speculative:            0.067 GB
Throttled:              0.000 GB
Free Memory:            0.016 GB
Compressed:             0.937 GB
Total:                  7.981 GB

Activity Monitor memory
App Memory:             2.586 GB
Wired Memory:           2.174 GB
Compressed:             0.937 GB
Memory Used:            5.698 GB
Cached Files:           2.268 GB
Total:                  7.981 GB

Swap Used:              0.508 GB    520.000 MB
Memory Pressure:        3.1   GB     39 percent

So, two ways of presenting numbers which add up to very nearly 8GB. The numbers are all in RAM sizes which are based on powers of 2, i.e. 1KB RAM is 1024 bytes.

Plus, at the end, swap used and memory pressure.

Note that "Compressed" means the physical RAM which is used by the Compressor which has compressed a hopefully larger amount of uncompressed RAM.

Here is the (not very elegant) python script:

#!/usr/bin/python

import sys, subprocess, re

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

# Get memory info from VM_STAT andprocess into a dictionary
vm = subprocess.Popen(['vm_stat'], stdout=subprocess.PIPE).communicate()[0]
# Process vm_stat
vmLines = vm.split('\n')
sep = re.compile(':[\s]+')
vmStats = {}
for row in range(1,len(vmLines)-2):
    rowElements = sep.split(vmLines[row].strip())
    vmStats[(rowElements[0])] = int(rowElements[1].strip('\.')) * 4096

# 2 quantities from sysctl
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])   # MBytes

# Pressure - just get the pressure value
sy = subprocess.Popen(['memory_pressure'], stdout=subprocess.PIPE).communicate()[0]
p1 = sy.find('tage:')
p2 = sy.find('%')
mp = 100 - int(sy[p1+6:p2])

# There are 2 tricks to get Activity Monitor's App Memory (which is best?)
#appMemory = page_pageable_internal_count - vmStats["Pages purgeable"] 
appMemory = vmStats["Anonymous pages"] - vmStats["Pages purgeable"] 

print 'Traditional memory:'
print 'Wired Memory:\t\t%9.3f GB' % ( vmStats["Pages wired down"] * f1 )
print 'Active Memory:\t\t%9.3f GB' % ( vmStats["Pages active"] * f1 )
print 'Inactive Memory:\t%9.3f GB' % ( vmStats["Pages inactive"] * f1 )
print 'Speculative:\t\t%9.3f GB' % ( vmStats["Pages speculative"] * f1 )
print 'Throttled:\t\t%9.3f GB' % ( vmStats["Pages throttled"] * f1 )
print 'Free Memory:\t\t%9.3f GB' % ( vmStats["Pages free"] * f1 )
print 'Compressed:\t\t%9.3f GB' % ( vmStats["Pages occupied by compressor"] * f1 )
# These add up close to phyical RAM
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"]) * f1 )
print ''
print 'Activity Monitor memory'
print 'App Memory:\t\t%9.3f GB' % ( appMemory * f1 )
print 'Wired Memory:\t\t%9.3f GB' % ( vmStats["Pages wired down"] * f1 )
print 'Compressed:\t\t%9.3f GB' % ( vmStats["Pages occupied by compressor"] * f1 )
print 'Memory Used:\t\t%9.3f GB' % ( (appMemory + vmStats["Pages wired down"] + vmStats["Pages occupied by compressor"] ) * f1 )
print 'Cached Files:\t\t%9.3f GB' % ( (vmStats["File-backed pages"] + vmStats["Pages purgeable"]) * f1 )
# and these add up to physical rAM
print 'Total:\t\t\t%9.3f GB' % ( (appMemory + vmStats["Pages wired down"] + vmStats["Pages occupied by compressor"] + vmStats["File-backed pages"] + vmStats["Pages purgeable"] + vmStats["Pages free"]) * f1)
print ''
print 'Swap Used:\t\t%9.3f GB  %9.3f MB' % ( swapUsed * 0.0009765625, swapUsed )
print 'Memory Pressure:\t%7.1f   GB %6.0f percent' % ( (appMemory + vmStats["Pages wired down"] + vmStats["Pages occupied by compressor"] + vmStats["File-backed pages"] + vmStats["Pages purgeable"] + vmStats["Pages free"]) * f1 * mp / 100, mp) 
    
sys.exit(0);

I use a very similar script called by the snmpd daemon to provide input to Cacti. This displays activity in graphical format, like this:

Cacti

That is for the last 24 hours (my MacBook was sleeping for some of that) with the numbers being the most recent values of each parameter.

3
  • 1
    Nice. I get a total of 31.998 GB for my 32 GB of RAM. Also, never apologise for python!
    – benwiggy
    Jul 8 at 11:12
  • Alllllllessss klar digga. Crazy one vote up for the effort alone Jul 8 at 19:20
  • Fantastic quality answer. Answers my question (The "Memory Used" stat) while providing detailed info on calculating other relevant values. Jul 9 at 15:36

You must log in to answer this question.

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