Guides

Is it a memory leak, or just a big app?

Almost everything people call a memory leak is an app doing what it was built to do. The difference is measurable in an afternoon.

"Memory leak" has become the label for any app that uses more memory than someone expected. Most of the time that app is fine and the expectation was wrong. Sometimes it really is leaking. The two look identical in a single screenshot and completely different over two hours.

The signature of an actual leak

A leak is memory an app allocates and then loses track of. That produces three symptoms:

  1. Growth that does not stop while the app is doing nothing new. Not growth when you open a document: growth while it sits idle.
  2. Growth that never reverses. A normal app's footprint rises and falls as you use it. A leaking one only ratchets.
  3. A restart fixes it completely, and then it starts again from the bottom.

Point three is the one that makes leaks tolerable and also the one that makes them annoying: quitting and reopening the app returns every byte, and tomorrow you do it again.

The test

Find the process, then watch it. Nothing here needs sudo.

top -l 1 -o mem -n 10 -stats pid,command,mem

Take the pid of the app you suspect, then sample it over time. Save this as leakwatch.sh, make it executable with chmod +x leakwatch.sh, and run it as ./leakwatch.sh 1234:

#!/bin/sh
# usage: leakwatch.sh <pid> [interval_seconds] [samples]
pid=$1; int=${2:-300}; n=${3:-12}
printf 'time      footprint   peak\n'
i=0
while [ $i -lt $n ]; do
  cur=$(/usr/bin/footprint -p "$pid" 2>/dev/null | awk '/phys_footprint:/{print $2, $3}')
  pk=$(/usr/bin/footprint -p "$pid" 2>/dev/null | awk '/phys_footprint_peak:/{print $2, $3}')
  [ -z "$cur" ] && { echo "pid $pid is gone"; exit 1; }
  printf '%s  %-11s %s\n' "$(date +%H:%M:%S)" "$cur" "$pk"
  i=$((i+1))
  if [ $i -lt $n ]; then sleep "$int"; fi
done

The defaults sample every five minutes, twelve times, so it runs for an hour and then stops. Do something else while it runs, and crucially, do not use the app you are watching for that hour.

Reading the output

What the column doesVerdict
Footprint flat, peak above it Healthy. It was busier earlier and gave the memory back. Finder on the machine used for these guides read 110 MB current against a 209 MB peak.
Footprint rises while you are not touching the app, and never dips This is the leak signature. Note the rate: MB per hour is what you report.
Footprint rises and falls with what you are doing Normal. That is a working set, not a leak.
Footprint far below peak, and the peak is enormous Not a leak, but worth knowing about: the app took that much once and will again. Docker on the measured machine sat at 0.47 GB with a 2.75 GB peak.

A worked example of the reporting format, from a user on r/elgato who traced an app leaking roughly 630 MB per day to a telemetry heartbeat: rate per day, plus what the app was doing at the time. That is the shape of a report a developer can act on. "It uses too much memory" is not.

Browsers are the special case

A browser growing over a day is usually not leaking. Each tab is its own renderer process with its own footprint, and they are all grouped under one name in Activity Monitor, so twenty tabs look like one enormous app.

Test it properly: close every tab except one, wait ten minutes, and sample again. If the total drops to something small, there was never a leak, only tabs. If it stays high with one tab open and keeps climbing, now you have something. Our measured reading shows what the grouping looks like: Chromium at 22 processes for 1.04 GB, Vivaldi at 15 for 3.61 GB.

What you can do about someone else's leak

This is the honest part. If the leak is in an app you did not write, you cannot fix it. You have four options and only one of them is free of trade-offs.

  1. Report it, with the rate. MB per hour or per day, the version number, and what the app was doing. This is the only action that ends the problem permanently.
  2. Quit and reopen the app when it gets large. The only action that genuinely returns the memory. Everything else is a way of tolerating it.
  3. Automate that restart so you are not the one watching. A rule on a threshold is the mechanical version of what you would otherwise do by hand every afternoon.
  4. Suspend it when you are not using it. This stops the growth rather than reversing it: a suspended process keeps what it already took. Useful for getting through the rest of the day, not a fix.

What does not work: apps that offer to free the leaked memory. The memory is still allocated by the leaking process and only that process can release it. See what memory cleaners actually change.

Options three and four are what RAMKeeper does, and it is worth saying plainly that they are workarounds for someone else's bug rather than cures. Option one is still the one that matters, and the rate from the script above is what makes that report land.

The short version

  • A leak grows while the app is idle and never comes back down. Measure for an hour.
  • Use /usr/bin/footprint -p <pid>, which also prints the peak.
  • Rising and falling with your work is a working set, not a leak.
  • For browsers, close the tabs first and then re-measure.
  • You cannot fix another developer's leak. Report the rate, then restart or govern it.

Disclosure: published by RAMKeeper, which sells a Mac memory tool. The script above was run before publishing, on 11 September 2026, and uses only commands that ship with macOS.