The honest engineering of pausing background apps on macOS

One of the things Shiny does is pause apps that have been idle for hours and are still using a lot of memory. macOS resumes them instantly when you click back, the same way Sleep mode does. The mechanism is simple, well-documented, and surprisingly underused. Here is how it works.

I'm Theodore Harding, the person who built Shiny. This post is a technical writeup of a specific feature: the ability to pause background apps that have been sitting idle for hours while holding onto significant resident memory. It is not a sales pitch. If you want to understand the mechanism, this is the honest version.

Most of what Shiny does that touches memory is well-understood macOS plumbing. The pausing feature is the clearest example of that. Let me walk through it properly.

The signal: SIGSTOP and SIGCONT

POSIX defines a set of signals that any Unix-family operating system can send to a process. Two of them are particularly relevant here: SIGSTOP and SIGCONT.

SIGSTOP tells a process to freeze. Every thread it is running stops executing immediately. The process remains in memory, with all its state intact, but it does not get scheduled by the kernel until it receives another signal. SIGCONT is that other signal: it tells the process to resume from exactly where it stopped.

These are not obscure or experimental. SIGSTOP and SIGCONT are part of POSIX.1-2001 and have been present in Apple's BSD-derived kernel since OS X 10.0. Apple's own documentation covers them in the Process and Thread Programming Guide. Activity Monitor exposes them via its "Send Signal to Process" menu. They are built into the platform.

What Shiny does is automate the decision about when to send them. When an app has been in the background for several hours, is not playing audio, is not actively syncing, and is holding more than a meaningful threshold of resident memory, Shiny sends it SIGSTOP. When you click back into it, Shiny sends SIGCONT before the app comes forward. From your perspective, the app was just there, a little slower to draw its first frame, same as coming back from sleep.

The related concepts: whether to quit apps or leave them open and whether closing apps actually frees RAM both touch this same territory from different angles.

Why this is safe

The main concern people raise is whether pausing an app will cause it to lose data. The answer is no, for a structural reason: SIGSTOP freezes the process at the kernel level. It does not ask the app to pause. It does not interrupt the app mid-execution in a way that leaves data structures in an inconsistent state. The kernel simply stops scheduling that process's threads, while leaving every in-memory value, every open file descriptor, and every network socket exactly as they were.

This is how App Nap works, too. Apple introduced App Nap in OS X Mavericks to reduce CPU and timer activity for background apps. The underlying mechanism is similar: the OS reduces or halts the scheduling of processes that are not visible and not doing something the user can hear. SIGSTOP is more aggressive (a complete halt rather than a throttle) but it operates on the same principle: the OS knows exactly what state a process is in, and it can hold that state indefinitely.

macOS tracks process state precisely. The kernel knows which processes are stopped, which are sleeping, which are runnable. A stopped process is not in an error state; it is in a defined, stable state that the kernel was designed to handle. Resuming it is not recovery. It is continuation.

The only scenario where SIGSTOP could cause a problem is if the signal arrives at the exact moment a process is mid-write to disk. Shiny waits for idle indicators (no recent CPU activity, no open write handles to active files) before sending the signal, which makes this edge case practically unreachable for the apps it targets.

What it actually frees

This is where I want to be precise, because "freeing memory" is an overloaded phrase that means different things in different contexts.

When Shiny pauses an app, the app's resident set does not immediately vanish. The resident set is the portion of a process's virtual address space that is currently mapped to physical RAM pages. When a process stops executing, the kernel no longer needs to keep those pages hot. Under memory pressure, the kernel's pager is free to reclaim those physical pages for other uses. The data is not lost: if the process later needs a page that was reclaimed, macOS pages it back in from the backing store (compressed memory first, then swap if necessary).

What this means in practice: pausing a background app does not instantly return 500 MB to your free memory count. What it does is make those pages available for reclamation. Under the memory pressure that makes your Mac feel sluggish, the kernel will reclaim them quickly. The result is that the apps you are actively using get more physical RAM to work with, and macOS's memory compressor has less to do.

What pausing does not touch: wired memory (the kernel's own pages and pages that drivers have locked), kernel pages, or pages that other processes have explicitly shared with the paused app. Those stay where they are. Shiny is not touching kernel memory. It is only influencing when the kernel's pager is permitted to reclaim user-space pages from an idle process.

The edge cases I had to handle

Not every background app is a safe candidate for pausing. Working through the exceptions was most of the engineering work here.

Apps that sync in the background. Dropbox, iCloud Drive, and similar apps do meaningful work while backgrounded. They watch directories, compute hashes, and upload changed files. Pausing them would delay sync without the user knowing why. Shiny checks whether a process has shown meaningful CPU or disk activity in the recent window before pausing it. Apps that are genuinely working get left alone.

Apps with timers that matter. Some apps set timers that fire on a schedule: reminder apps, calendar apps, communication tools that poll for new messages. A paused process cannot fire its own timers. Shiny treats any app in the system's scheduled-delivery list as ineligible for pausing. For communication apps specifically, the user generally wants to know about new messages promptly, so they are excluded entirely.

Apps that should never be paused. A fixed exclusion list covers categories where pausing is always wrong: audio apps (pausing a music player mid-playback would be jarring), screen-recording apps, apps with active network servers, and accessibility tools. The list is conservative. When in doubt, Shiny leaves the app alone.

System processes. Shiny only considers user-space processes that have a visible window or menu-bar presence. It never touches system daemons, kernel extensions, or processes owned by root. Applying SIGSTOP to a system process that a user application depends on would be a serious mistake, and Shiny's candidate selection ensures it never happens.

Why this is not magic

I want to be clear about something: Shiny is not doing anything heroic here. SIGSTOP and SIGCONT have been in macOS since the beginning. Activity Monitor has exposed them in its interface for years. Any developer with a process ID and a terminal can do this manually with kill -STOP and kill -CONT.

What Shiny does is make the decision automatically, correctly, and quietly. It evaluates which apps are genuinely idle and holding meaningful memory. It excludes the ones where pausing would be wrong. It sends SIGCONT before the app comes forward so the resume is seamless. The mechanism is Apple's. The judgment is Shiny's.

"Pausing a background app is not a hack. It is using a piece of macOS that has been there since OS X 10.0."

If you want to understand more about why some of these decisions were made at the product level, why I built Shiny covers the broader context. For the question of whether this kind of memory management is actually worth caring about, does closing apps free RAM on Mac goes into the underlying memory model in more depth.

The short version: this is built into macOS. Apple supports it. Shiny's job is choosing wisely when to use it.

Common follow-up questions

Will pausing an app cause it to lose data?
No. SIGSTOP freezes a process exactly where it is in memory. All in-memory state, open file handles, and unsaved data remain intact. When Shiny sends SIGCONT, the process resumes from precisely where it stopped. The only risk would be a race condition where the app was mid-write at the exact moment of the signal, and Shiny waits for idle indicators before pausing to avoid this.
Is SIGSTOP the same as quitting an app?
No. Quitting an app sends SIGTERM (or SIGKILL), which asks the process to shut down and deallocates all its resources. SIGSTOP does not terminate the process. It suspends execution while leaving everything in place. The app is still in memory, still has its open files, and still appears in your Dock. It simply stops using CPU until SIGCONT is sent.
Why does macOS not pause idle apps automatically?
It does, partially, through App Nap. App Nap reduces the CPU priority and timer frequency of apps that are not visible and not playing audio. But App Nap does not pause apps completely, and it does not reclaim resident memory. SIGSTOP goes further, which is why Shiny uses it selectively for apps that are both idle and holding significant memory.
Can I pause an app manually with Activity Monitor?
Yes. Select the process in Activity Monitor, then go to View > Send Signal to Process and choose SIGSTOP. You can resume with SIGCONT the same way. Shiny automates this decision based on idle time and memory usage, so you don't have to evaluate each app yourself.
Does pausing an app save battery too?
Yes. A paused process uses essentially zero CPU. Background apps that poll for updates, run timers, or perform periodic network checks stop doing all of that while paused. On a MacBook this translates directly to less heat and longer battery life for the session.