Skip to content

[Bug] #183

@maxwilliamdev

Description

@maxwilliamdev

感谢你向 ClashX 提交 issue!
在提交之前,请确认:

  • 我已经在 ……/ 中找过我要提出的问题
  • 这是 ClashX UI层面的问题,并非 Clash Core 的问题(例如xx软件连不上,无法连接特定服务器等)。其他 Clash 衍生版本没有次问题。
  • 如果你可以自己 debug 并解决的话,提交 PR 吧!

我都确认过了,我要继续提交。


clashX config

selectOutBoundMode = rule
selectConfigName = "clash_meta"
showNetSpeedIndicator = 0
restoreTunProxy = 1
restoreSystemProxy = 0

ClashX log

与代理核心通信正常,无异常日志输出。
高 CPU 占用不伴随日志错误,为 UI 层渲染循环问题。

ClashX Crash log

无崩溃。进程正常运行但持续高 CPU 占用。

环境 Environment

  • 使用者的操作系统:macOS 26.4 (Build 25E246, Apple Silicon ARM64)
  • ClashX Meta 版本:v1.4.31 (640)
  • 网络环境:家庭网络,正常使用
  • ISP:无 DNS 污染
  • 其他:问题在 macOS 26 上出现,此前在旧版 macOS 上未出现

说明 Description

ClashX Meta 主进程(非 Clash Core)在 macOS 26.4 上持续占用约 50% CPU。通过 sample 采样分析,几乎 100% 的 CPU 时间消耗在
NSStatusItem(菜单栏图标)的重绘上,而非代理核心的网络处理。

核心问题:macOS 26 的私有框架 UpdateCycle(UC::DriverCore::continueProcessing())在每次 RunLoop 迭代都触发 Core Animation
事务提交,导致 ClashX 的 NSStatusBarButtonCell 每秒被重绘数百次。

此外,退出 ClashX 主程序后,以 root 权限运行的 com.metacubex.ClashX.ProxyConfigHelper(PID
43717)未被正常终止,因主程序消失导致连接断开后进入重试死循环,CPU 飙升至约 200%。

重现问题的具体步骤 Steps to Reproduce

  1. 在 macOS 26.4 上启动 ClashX Meta v1.4.31
  2. 正常使用代理功能,无需任何特殊操作
  3. 观察 Activity Monitor 中 ClashX Meta 进程的 CPU 占用

我预期会发生……?

ClashX Meta 正常运行时 CPU 占用应较低(通常 < 5%),菜单栏图标仅在有状态变化时更新。

实际上发生了什麽?

  • ClashX Meta 主进程 CPU 持续占用 ~50%,通过 sample 工具分析,3 秒内采集 2143 个样本(~714 次/秒),几乎全部消耗在
    NSStatusBarButtonCell drawWithFrame:inView: → NSViewBackingLayer display 的重绘循环中
  • 即使关闭「显示网速」选项(showNetSpeedIndicator = 0),问题依然存在
  • sample 调用链显示:UC::DriverCore::continueProcessing() (UpdateCycle) → CA::Transaction::commit() →
    CA::Layer::display_if_needed() → NSViewBackingLayer display → NSStatusBarButtonCell drawWithFrame:inView:
  • 3 秒内 NSStatusBarButtonCell 重绘 191 次,NSViewBackingLayer display 369 次
  • 退出 ClashX 后,ProxyConfigHelper 残留进程 CPU 占用 ~200%

可能的解决方案 Possible Solution

  1. NSStatusItem 渲染优化:macOS 26 引入了 Scene-based status
    item(NSSceneStatusItem、NSStatusItemScene),渲染管线发生变更。建议在每次 RunLoop 事务提交时检查 NSStatusItem
    内容是否实际发生了变化,避免无意义的重绘。可参考 Apple 对 NSStatusItem 在 macOS 26 中的变更说明
  2. 降级 Core Animation 事务刷新频率:当前 UC::DriverCore 驱动的事务在每个 RunLoop
    迭代都触发,可考虑对状态栏图标的更新做节流(throttle),例如限制到每秒最多 1-2 次
  3. ProxyConfigHelper 生命周期管理:主程序退出时应主动向 ProxyConfigHelper 发送终止信号,而非依赖 helper
    自行检测主程序状态,避免因连接断开导致的重试死循环

更多信息 More Information

sample 分析完整调用链(关键部分):

Call graph:
2143 Thread_738305: Main Thread
+ 2143 NSApplicationMain
+ 2143 -[NSApplication run]
+ 2143 RunCurrentEventLoopInMode
+ 2136 _CFRunLoopRunSpecificWithOptions
+ 686 __CFRunLoopDoSource1
+ 686 UC::DriverCore::continueProcessing() (in UpdateCycle)
+ 682 stepTransactionFlush
+ 681 CA::Transaction::flush_as_runloop_observer
+ 631 CA::Transaction::commit()
+ 530 CA::Context::commit_transaction
+ 524 CA::Layer::display_if_needed
+ 369 -[NSViewBackingLayer display]
+ 338 -[NSViewBackingLayer drawInContext:]
+ 328 -[NSView _recursive:displayRectIgnoringOpacity:inContext:]
+ 239 -[NSControl drawRect:]
+ 191 -[NSStatusBarButtonCell drawWithFrame:inView:]
+ 188 -[NSSystemStatusBar drawBackgroundInRect:inView:]
+ 188 -[NSSceneStatusItem _setSelectedContentFrame:options:]
+ 188 -[NSStatusItemScene updateSettings:transition:]

活跃维护的替代客户端(如 ClashVerge Rev、Clash Nyanpasu 等)因使用 Tauri/Web 技术栈渲染 UI,不依赖 macOS 原生
NSStatusItem,不受此问题影响。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions