Skip to content

ClashMacDashboard CPU 占用 200%+ 问题报告 #247

@Penghaiku

Description

@Penghaiku

ClashMacDashboard CPU 占用 200%+ 问题报告

基本信息

  • 应用: ClashMac (ClashMacDashboard 组件)
  • 版本: 26.6 (build 128)
  • 系统: macOS 26.2 (25C56)
  • 硬件: Apple M4, 32GB RAM

问题描述

ClashMacDashboard 进程 CPU 占用率持续在 200%+,导致系统发热、风扇高速运转。

现象详情

CPU 占用情况

PID    COMMAND          %CPU TIME      #TH
40215  ClashMacDashboard 203.6 421:38  4

进程信息

  • PID: 40215
  • 启动时间: 2026-01-31 13:27:19
  • 持续时间: 约 7 小时后出现 CPU 飙升
  • 物理内存占用: 330.8 MB (峰值 428.4 MB)

调用栈分析

通过 sample 工具采集 5 秒 CPU 样本,发现进程陷入 SwiftUI 布局死循环

核心调用栈 (递归深度 > 50):

RunCurrentEventLoopInMode (HIToolbox)
  _CFRunLoopRunSpecificWithOptions (CoreFoundation)
    __CFRunLoopRun (CoreFoundation)
      __CFRunLoopDoSources0 (CoreFoundation)
        __CFRunLoopDoSource0 (CoreFoundation)
          UC::DriverCore::continueProcessing() (UpdateCycle)
            stepTransactionFlush (AppKit)
              CA::Transaction::flush_as_runloop_observer (QuartzCore)
                CA::Transaction::commit()
                  NSDisplayCycleFlush (AppKit)
                    __NSWindowGetDisplayCycleObserverForLayout_block_invoke
                      -[NSWindow _layoutViewTree]  ← 递归开始
                        -[NSView layoutSubtreeIfNeeded]
                          _layoutSubtreeIfNeededAndAllowTemporaryEngine:
                            _layoutSubtreeWithOldSize:  ← 死循环点
                              (无限递归 50+ 层)
                                NSHostingView.layout() (SwiftUI)
                                  invalidateSizeConstraintsIfNecessary()
                                    minSize()
                                      _sizeThatFits()

问题定位:

  • 调用栈显示 _layoutSubtreeWithOldSize 方法无限递归
  • 涉及 NSHostingView.layout()invalidateSizeConstraintsIfNecessary()minSize()_sizeThatFits() 循环
  • 这是典型的 SwiftUI 布局计算 bug,当视图约束条件冲突时可能触发

影响范围

  • Clash 核心 (mihomo) 运行正常,网络代理功能未受影响
  • Dashboard UI 完全无响应(无法点击、无法关闭窗口)
  • 系统资源: 持续占用 2 个 CPU 核心,风扇高速运转
  • 用户体验: 必须强制杀死进程才能恢复

复现步骤

尚未找到稳定复现方法,但观察到以下模式:

  1. Dashboard 持续运行约 5-7 小时后出现
  2. 期间正常使用 SSH、EasyTier、网页浏览等
  3. 可能与窗口大小调整、显示器切换或长时间后台运行有关

临时解决方案

# 强制终止 Dashboard 进程
kill -9 40215

# 然后点击菜单栏 Clash 图标重新打开 Dashboard

注意: 终止 Dashboard 不会影响网络代理,mihomo 核心进程仍在运行。

附加信息

网络环境

  • 使用 TUN 模式 (utun5: 198.18.0.1)
  • 同时运行 EasyTier VPN (utun0: 10.86.86.3)
  • 配置文件: /Users/betterman/Library/Application Support/clashmac/work/config.yaml
  • 问题根本原因:Clash 配置中对 RustDesk (vps:21114)
    的路由规则导致持续连接尝试,当 RustDesk 服务不可达时产生大量 connection refused
    错误,Clash 日志记录这些错误,ClashMacDashboard
    在实时渲染和处理这些大量错误日志时触发了 UI 更新循环,导致 CPU 占用飙升到 190%

相关日志

mihomo 核心日志显示网络连接正常,无异常错误。

已保存的诊断文件

  • CPU 样本: /tmp/ClashMacDashboard_2026-01-31_190122_lPdU.sample.txt
  • mihomo 日志: ~/Library/Application Support/clashmac/logs/mihomo.log

期望行为

Dashboard 应该正常响应用户操作,CPU 占用率保持在正常水平 (< 10%)。

实际行为

Dashboard 陷入无限布局循环,CPU 占用 200%+,UI 完全无响应。

建议修复方向

  1. 布局约束检查: 检查 SwiftUI 视图的 size constraints 是否存在循环依赖
  2. 递归深度限制: 添加布局计算的最大递归深度限制
  3. 错误恢复: 当检测到布局循环时,优雅地降级或重置视图状态
  4. 调试日志: 在 debug 模式下添加布局计算的详细日志

报告时间: 2026-01-31 19:05 CST

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions