Memory Penguin is a lightweight macOS menu bar app that shows current memory pressure with a small penguin icon. Click the menu bar icon to inspect effective memory use, physical occupancy, swap activity, top memory processes, top CPU processes, and temporary CPU controls for selected high-usage processes.
The app is built with Swift and AppKit. It does not require Electron or any extra runtime.
Memory Penguin was developed through collaboration between the user and Codex. The code, feature changes, README, and build workflow were assisted by Codex.
The app icon and menu bar icon assets were generated by ChatGPT 5.5 and then integrated into the macOS app bundle.
Memory Penguin is inspired by Stats, a macOS menu bar system monitor by Serhiy Mytrovtsiy and contributors.
| Calm | Elevated | High |
|---|---|---|
![]() |
![]() |
![]() |
| Normal memory pressure | Elevated memory pressure | High memory pressure |
The menu bar uses three pre-generated 48 x 44 transparent PNG assets. The app loads and caches the matching asset for each pressure state; it no longer crops or removes the sprite-sheet background at runtime. The original Resources/memory_icon.png sprite sheet remains in the repository and app bundle as the source artwork.
- Shows the effective used memory estimate percentage and memory pressure state in the menu bar.
- Uses three penguin icon states for memory pressure:
- Calm: short green mark
- Elevated: medium yellow mark
- High: long red mark
- Toggles whether the menu bar percentage is shown.
- Toggles detailed memory information in the menu.
- Enables or disables Launch at Login.
- Displays memory details:
- Total
- Effective used estimate
- Physical occupied
- Reclaimable estimate
- Kernel free, including speculative pages
- Bounded anonymous estimate
- Bounded file-backed estimate
- Raw file-backed and anonymous counters
- Active
- Inactive
- Wired
- Compressed
- Purgeable
- Speculative
- Page-out rate
- Swap traffic rate
- Swap used / available / total
- Displays top memory processes and top CPU processes.
- Lets you click a top CPU process to add it to a temporary CPU limit list.
- Supports these CPU limit modes:
- Background Priority
- Run 75% of Time
- Run 50% of Time
- Run 25% of Time
- Remove Limit
- Validates each limited process by PID, owner UID, and microsecond-resolution start time before every control signal.
- Rejects PID 0/1, other users' processes, Memory Penguin itself, and protected macOS interface or system processes.
- Uses an independent heartbeat resume guard so a stopped process is resumed if Memory Penguin exits unexpectedly or its main loop stops responding.
- macOS 13 Ventura or later
- Xcode Command Line Tools
- Swift 6 toolchain
Install Xcode Command Line Tools:
xcode-select --installClone or download the project, then run this from the project root:
chmod +x Scripts/build-app.sh
Scripts/build-app.shThe app bundle and portable archive will be created at:
dist/MemoryPenguin.app
dist/MemoryPenguin.zip
The archive is created from the clean signed staging bundle and independently extracted and verified by the build script. This prevents Desktop file-provider metadata from being stored inside the distributable app.
Run the app:
open dist/MemoryPenguin.appFor regular use, prefer launching the .app bundle instead of using swift run. The app bundle applies LSUIElement, which lets Memory Penguin run as a Dockless menu bar utility.
Move the built app into /Applications:
cp -R dist/MemoryPenguin.app /Applications/
open /Applications/MemoryPenguin.appIf you want to use Launch at Login, place the app in /Applications first, then enable Launch at Login from the Memory Penguin menu.
The build script ad-hoc signs the local app bundle so macOS can register it as a login item. This is not a notarized release. If you plan to distribute the app publicly, use a proper Developer ID signature and notarization flow.
Run the app directly during development:
swift runswift run does not fully reproduce the app bundle's LSUIElement behavior. To test the normal menu bar app experience, use:
Scripts/build-app.sh
open dist/MemoryPenguin.appFor each intentional release or user-facing change, add an entry under Unreleased in CHANGELOG.md. When preparing a release, move those entries into a dated version section and update CFBundleShortVersionString in Resources/Info.plist to the same version. Scripts/build-app.sh reads that version and updates the bundled CFBundleVersion to a timestamp build number.
Regenerate the transparent status icons and README previews after changing the source sprite sheet:
swift Scripts/generate-icon-previews.swiftOn macOS 14 or later, the generator uses the system Vision foreground mask to preserve the black penguin while removing the dark background.
Run the core self-tests from the project root:
swift run MemoryPenguinCoreSelfTestsThe self-test executable verifies the reusable core logic without launching the menu bar app. It covers effective used, reclaimable, and physical occupancy calculations; activity rates; memory pressure mapping; ps parsing; process sorting; PID reuse detection; owner and protected-process checks; and duty-cycle labels.
Run the resume guard integration test after building the executable:
swift build --product MemoryPenguin
swift Scripts/ResumeGuardIntegrationTest.swiftThe integration test creates its own /bin/sleep children, confirms they enter SSTOP, and verifies that both a closed heartbeat pipe and a two-second heartbeat timeout restore them.
CPU limiting is session-based. A limit is bound to the selected PID, effective owner UID, and process start time; if the PID exits and is reused, Memory Penguin refuses to signal the replacement process.
Background Priority uses macOS taskpolicy -b. This is a gentle limit that lowers scheduling priority, but it does not guarantee a fixed CPU percentage.
Duty-cycle modes use periodic SIGSTOP / SIGCONT signals to pause and resume the process. Run 50% of Time means the process runs for roughly half of each one-second period; it does not mean an absolute 50% CPU ceiling. A four-worker process that previously consumed about 400% CPU may still average around 200% CPU under this mode.
Each duty-cycle process has a helper mode of the same signed executable watching a heartbeat pipe. If Memory Penguin crashes or is force-quit, the pipe closes and the helper resumes the exact original process. If the app remains alive but stops sending heartbeats, the helper resumes the process after two seconds. Normal removal also resumes the process and removes background priority.
Duty-cycle control can still make GUI, audio, download, compiler, or I/O-heavy applications temporarily unresponsive. Protected system processes and processes owned by another user are not controllable.
The project includes a CPU stress test utility for testing the top CPU process list and CPU limiting behavior.
Compile it first so the process list shows a clear CPUStressTest process name:
swiftc Scripts/CPUStressTest.swift -o /tmp/CPUStressTest
/tmp/CPUStressTest --workers 2 --seconds 120You can also run it directly as a Swift script:
Scripts/CPUStressTest.swift --workers 2 --seconds 120Test flow:
- Run
CPUStressTest. - Open the Memory Penguin menu.
- Find
CPUStressTestunderTop CPU Processes. - Click
CPUStressTestto add it toLimited Processes. - Choose
Run 50% of Timeor another limit mode from the submenu. - Click the checked top CPU process again, or choose
Remove Limitfrom theLimited Processessubmenu, to remove the limit.
When the menu is closed, Memory Penguin updates lightweight memory information every 2 seconds and does not read the process list.
When the menu is open, Memory Penguin updates every 1 second and reads the process snapshot on a background queue to refresh the top memory and top CPU process lists without blocking the menu UI.
Memory data sources:
host_statistics64sysctlkern.memorystatus_vm_pressure_level
Process list source:
/bin/ps -axo pid=,rss=,pcpu=,comm=The app reads a ps snapshot and sorts the processes in app code. Launch failures, nonzero exits, and invalid output are shown as Process list unavailable rather than being presented as an empty process list.
Activity Monitor's full memory pressure formula is not a public API. Memory Penguin uses macOS kern.memorystatus_vm_pressure_level as its pressure state source and maps it to:
- Calm
- Elevated
- High
The percentage shown in the menu bar is an effective used memory estimate, not Activity Monitor's private memory pressure percentage. macOS memory pressure remains the authoritative health signal.
Current memory model:
- Physical occupied: total physical memory - kernel free count
- Kernel free: capped to total physical memory;
vm_statistics64documents that this count already includes speculative pages - Non-free file-backed estimate: file-backed memory - speculative memory, floored at zero
- Reclaimable estimate: non-free file-backed estimate + purgeable memory, capped to physical occupied memory
- Effective used estimate: physical occupied - reclaimable estimate
- Anonymous estimate: anonymous counter capped to physical occupied memory
- File-backed estimate: file-backed counter capped to physical occupied memory
Active/inactive state, anonymous/file-backed backing, and purgeable status are overlapping classification dimensions. Memory Penguin normalizes speculative pages before estimating reclaimable memory and continues to display the raw counters separately for transparency.
Sources/MemoryPenguin/main.swift App menu, status item, and UI wiring
Sources/MemoryPenguinCore/ Reusable memory/process/core logic
Tests/MemoryPenguinCoreSelfTests/main.swift Core self-test executable
Resources/Info.plist macOS app bundle metadata
Resources/icon.png App icon
Resources/memory_icon.png Original menu bar sprite sheet
Resources/Generated/StatusIcons/ Bundled transparent menu bar icons
Scripts/build-app.sh Build app bundle
Scripts/CPUStressTest.swift CPU stress test utility
Scripts/ResumeGuardIntegrationTest.swift Resume guard process integration test
Scripts/generate-icon-previews.swift Status icon and preview generator
MIT License. See LICENSE.
Memory Penguin is a local-use utility. Duty-cycle control sends signals to other processes, so avoid limiting apps that are saving important data or workloads that cannot tolerate temporary pauses.


