A lightweight macOS menu bar system monitor. A donut gauge in the menu bar fills as memory usage rises. Click it for a popover with a large ring chart, live network throughput, CPU, and battery temperature.
轻量级 macOS 菜单栏系统监控工具。菜单栏小圆环随内存使用填充,点开是带大圆环、实时网速、CPU 和电池温度的弹窗。
| Menu bar | Popover (memory mode) | Popover (network mode) |
|---|---|---|
16-pt donut + percentage (or ↓X ↑Y in network mode), auto-tinted by system appearance. |
92-pt color-coded ring, end-cap dot that follows the trim, percentage in the center, used/total bytes, status caption. | Two stacked 16-bar rolling charts (download / upload) with the latest bar pulsing between samples. |
- Live donut gauge — 16-pt ring, system-foreground tint via
NSImage.isTemplate = true, redrawn only when displayed state changes. - Two display modes:
- memory — percentage text alongside the ring
- network —
↓1.2MB ↑234KBdownload/upload text
- Mode is picked from the popover and persisted to
UserDefaults. - Re-renders on appearance change (light ⇄ dark, Auto Dark Mode).
- The current menu-bar arc is vertically flipped relative to the earlier builds, so the fill starts from the lower half of the ring.
Click the menu bar icon to open a 292-pt wide SwiftUI popover:
- Mode picker — segmented control at the top: 内存使用 / 网速.
- Memory mode — a 92-pt ring with a 10-pt stroke:
- Color shifts green → orange → red at 60 % / 85 %
- A small end-cap dot rides the trim end (
.rotationEffectdriven by the same fraction) - The percentage is centered as a 22-pt rounded monospaced number with
.contentTransition(.numericText())so the digits roll over smoothly - A subtle shadow halo appears above 85 %
- Used / total bytes and a
稳定 / 偏高 / 告急status caption round out the row - The whole ring is GPU-rendered via
.drawingGroup()for retina crispness - The chart and metrics areas use a light grouped panel treatment for quicker scanning
- Network mode — two stacked rolling-window bar charts (download in blue, upload in green):
- 16 bars per chart, 2 s per sample, history ≈ 32 s
- Each bar's height is normalized to the window's max, so spikes always fill the chart
- The latest bar interpolates smoothly between real samples instead of adding decorative fake activity
- 1-pt baseline rule under each row keeps the eye anchored when traffic is near zero
- Data table — 内存 / CPU / 网络 / 温度, with monospaced values and per-row accent color.
- 退出 button to quit.
- Swift 6 + strict concurrency;
@MainActor @ObservableSystemMonitorposts asystemMonitorDidRefreshnotification on each 2 s tick. - Native macOS APIs only — no third-party dependencies:
host_statisticsfor CPUvm_statistics64for memorygetifaddrsfor network throughput (delta between samples)IORegistryfor battery temperature
- All charts animate via value-driven
.animation(.smooth, value:)or.animation(.easeInOut, value:)modifiers — the popover root does not use.id(refreshCounter), so in-flight transitions are never torn down by a forced rebuild. - The memory donut uses
.smooth(duration: 0.5)for its main transition. - The latest network bar (
LiveBar) interpolates from the previous sample to the current one over 2 seconds with an ease-out quadratic curve, so the chart flows smoothly between refresh ticks. - Historical bar heights use
.smooth(duration: 0.45)and the latest bar is timeline-driven. - ~1,440 lines of Swift.
Download MemBar.dmg from the Releases page.
Latest release: v1.1.2. This release fixes Settings opening from the popover and right-click menu, adds a provider-based metrics engine, and improves local release diagnostics while preserving the lightweight menu-bar experience.
Or via Homebrew (planned):
brew install --cask membar- Download
MemBar.dmgfrom the latest release - Open the DMG file
- Drag MemBar.app into the Applications folder
- Launch MemBar from Applications — the donut appears in the menu bar
Note: On first launch, macOS may show an unidentified developer warning. Right-click MemBar.app in Applications and select "Open" to bypass.
注意: 首次打开可能提示未识别的开发者, 请在访达中右键点击 MemBar.app → 打开。
- Launch MemBar — the donut gauge appears in the menu bar (top-right).
- Click the donut to open the popover.
- In the popover, use the picker to switch between 内存使用 and 网速.
- The picker choice is remembered between launches.
- Use 设置 in the popover, or right-click the donut and choose Settings, to open preferences.
- Right-click the donut for a "Quit MemBar" menu.
The gauge auto-tints with your system's light / dark appearance. Enable macOS Auto Dark Mode (System Settings → Appearance → Auto) to make it follow the time of day automatically.
# Requires macOS 15+ and a Swift 6 toolchain (Xcode 16 / Xcode 27 beta both work)
git clone https://github.com/d8dzmf5mfn/MemBar.git
cd MemBar/Monitor
open Monitor.xcodeproj
# Select target "Monitor" → Build & Run (⌘R)Or from the command line (with Xcode-beta):
cd MemBar/Monitor
DEVELOPER_DIR="$HOME/Downloads/Xcode-beta.app/Contents/Developer" \
xcodebuild -project Monitor.xcodeproj -scheme Monitor -configuration Release build
# Built .app will be in DerivedDataRun tests with DerivedData outside the workspace to avoid file-provider extended attributes interfering with local codesigning:
DEVELOPER_DIR="$HOME/Downloads/Xcode-beta.app/Contents/Developer" \
xcodebuild test -project Monitor/Monitor.xcodeproj -scheme Monitor \
-destination 'platform=macOS' \
-derivedDataPath /private/tmp/membar-derived-data./scripts/build-dmg.sh
# Produces MemBar.dmg in the current directoryThe build script:
- Runs
xcodebuildin Release configuration - Writes DerivedData to
/private/tmp/membar-dmg-derived-databy default, keeping build artifacts out of the repository - Clears extended attributes, ad-hoc signs the local app bundle, and creates a
MemBar.dmgusinghdiutil
Local DMG builds are ad-hoc signed only.
GitHub release builds still need Developer ID signing and notarization.
Monitor/
├── Monitor.xcodeproj/
├── Monitor/
│ ├── MemBarApp.swift # @main App, AppDelegate, NSStatusItem,
│ │ # StatusBarIconView, MenuBarRenderer
│ │ # (Core Graphics donut for the menu bar)
│ ├── Models/
│ │ └── MetricsData.swift # CPUSnapshot / MemorySnapshot /
│ │ # NetworkSnapshot / ThermalSnapshot
│ ├── MonitorEngine/
│ │ ├── CPUInfo.swift # host_statistics
│ │ ├── MemoryInfo.swift # vm_statistics64
│ │ ├── NetworkInfo.swift # getifaddrs
│ │ ├── SystemMonitor.swift # @MainActor @Observable, 2 Hz refresh,
│ │ │ # posts .systemMonitorDidRefresh
│ │ └── TemperatureInfo.swift # IORegistry
│ ├── Views/
│ │ └── MenuBarView.swift # popover: mode picker, donut + bar
│ │ # charts, data rows, quit button
│ └── Assets.xcassets/ # AppIcon, AccentColor
└── scripts/
└── build-dmg.sh # DMG packaging script
- Swift 6 with strict concurrency
- SwiftUI for the popover (
@Observable+Bindable) - AppKit for
NSStatusItem+ the menu bar renderer (CGContextdonut rasterized to a template-modeNSImage) - Core Graphics for the menu bar pixel rendering
- macOS 15+ native APIs:
host_statistics,vm_statistics64,getifaddrs,IORegistry
MIT