mn3我经常使用, mn4上使用一段时间后就会鼠标转圈圈, 100%的, 换了电脑, 升级了多次系统问题依旧

```
❯ marginnote4 软件再次卡住了, 转圈圈, 无法执行操作, 如何排查问题?

◐ The user says MarginNote 4 is frozen again right now (spinning wheel, can’t do anything). This is a live debugging situation. I should capture diagnostics immediately while it’s frozen - get a spindump/sample of the process to see what the
main thread is blocked on.

● Get MarginNote PID and current state (shell)

│ PID: 30236
│ PID %CPU %MEM RSS STAT
│ 30236 3.5 0.6 380464 S
│ <exited with exit code 0>

│ pid=$(pgrep -x “MarginNote 4”); echo “PID: $pid”; ps -p $pid -o pid,pcpu,pmem,rss,state | cat
└ 4 lines

● Sample MarginNote threads for 5 seconds while frozen (shell)

│ Output too large to read at once (675.2 KB). Saved to: /var/folders/51/y020gjv14kx9mpdqmw912t580000gn/T/copilot-tool-output-1778673590546-a97yzb.txt
│ Consider using tools like grep (for searching), head/tail (for viewing start/end), view with view_range (for specific sections), or jq (for JSON) to examine portions of the output.

│ Preview (first 500 chars):

│ Analysis of sampling MarginNote 4 (pid 30236) every 1 millisecond
│ Process: MarginNote 4 [30236]
│ Path: /Applications/MarginNote 4.app/Contents/MacOS/MarginNote 4
│ Load Address: 0x100f38000
│ Identifier: QReader.MarginStudy.easy
│ Version: 4.3.2 (32002)
│ Code Type: ARM64
│ Platform: Catalyst
│ Parent Process: launchd [1]
│ Target Type: live task

│ Date/Time: 2026-05-13 19:59:44.624 +0800
│ Launch Time: 2026-05-13 17:40:28.761 +0800
│ OS Version:
│ <exited with exit code 0>

│ sample 30236 5 2>/dev/null
└ 20 lines

● Extract main thread stack from sample (shell)

│ 3818 Thread_2266225: Main Thread DispatchQueue_
│ + 3818 start (in dyld) + 6992 [0x1811d7da4]
│ + 3818 ??? (in MarginNote 4) load address 0x100f38000 + 0x6c11dc [0x1015f91dc]
│ + 3818 UIApplicationMain (in UIKitCore) + 144 [0x1b9da4ed4]
│ + 3818 UINSApplicationMain (in UIKitMacHelper) + 972 [0x19f93c1bc]
│ + 3818 _NSApplicationMainWithInfoDictionary (in AppKit) + 24 [0x185c8d930]
│ + 3818 NSApplicationMain (in AppKit) + 880 [0x185a467b0]
│ + 3818 -[NSApplication run] (in AppKit) + 368 [0x185a6e13c]
│ + 3818 -[NSApplication(NSEventRouting) nextEventMatchingMask:untilDate:inMode:dequeue:] (in AppKit) + 72 [0x1866103a8]
│ + 3818 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] (in AppKit) + 688 [0x18661069c]
│ + 3818 _DPSNextEvent (in AppKit) + 576 [0x185a7b084]
│ + 3818 _DPSBlockUntilNextEventMatchingListInMode (in AppKit) + 228 [0x1861271a4]
│ + 3818 _BlockUntilNextEventMatchingListInMode (in HIToolbox) + 48 [0x18e5b113c]
│ + 3818 ReceiveNextEventCommon (in HIToolbox) + 272 [0x18e4277e4]
│ + 3818 RunCurrentEventLoopInMode (in HIToolbox) + 320 [0x18e424560]
│ + 3818 _CFRunLoopRunSpecificWithOptions (in CoreFoundation) + 532 [0x181721be0]
│ + 3818 __CFRunLoopRun (in CoreFoundation) + 820 [0x18164f4e4]
│ + 3818 __CFRunLoopDoSources0 (in CoreFoundation) + 232 [0x1816508c0]
│ + 3818 __CFRunLoopDoSource0 (in CoreFoundation) + 172 [0x181650b54]
│ + 3818 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION (in CoreFoundation) + 28 [0x181650bc0]
│ + 3818 WTF::RunLoop::performWork(void*) (in JavaScriptCore) + 36 [0x1d0b5edd8]
│ + 3818 WTF::RunLoop::performWork() (in JavaScriptCore) + 460 [0x1d0b5d830]
│ + 3818 WTF::Detail::CallableWrapper<IPC::Connection::SyncMessageState::processIncomingMessage(IPC::Connection&, WTF::UniqueRefIPC::Decoder&)::$_0, void>::call() (in WebKit) + 652
│ [0x1d3ccba34]
│ + 3818 IPC::Connection::SyncMessageState::ConnectionAndIncomingMessage::dispatch() (in WebKit) + 92 [0x1d3cac8d4]
│ + 3818 IPC::Connection::dispatchMessage(WTF::UniqueRefIPC::Decoder) (in WebKit) + 792 [0x1d3cb0f80]
│ + 3818 WebKit::WebProcessProxy::didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, WTF::UniqueRefIPC::Encoder&) (in WebKit) + 444 [0x1d3383548]
│ + 3818 WebKit::WebProcessProxy::dispatchSyncMessage(IPC::Connection&, IPC::Decoder&, WTF::UniqueRefIPC::Encoder&) (in WebKit) + 44 [0x1d3880dbc]
│ + 3818 IPC::MessageReceiverMap::dispatchSyncMessage(IPC::Connection&, IPC::Decoder&, WTF::UniqueRefIPC::Encoder&) (in WebKit) + 176 [0x1d3ccecdc]
│ + 3818 WebKit::WebPageProxy::didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, WTF::UniqueRefIPC::Encoder&) (in WebKit) + 6148 [0x1d331c30c]
│ + 3818 WebKit::WebPageProxy::interpretKeyEvent(WebKit::EditorState&&, WebKit::KeyEventInterpretationContext&&, WTF::CompletionHandler<void (bool)>&&) (in WebKit) + 192
│ [0x1d367c1a4]
│ + 3818 WebKit::PageClientImpl::interpretKeyEvent(WebKit::NativeWebKeyboardEvent const&, WebKit::KeyEventInterpretationContext&&) (in WebKit) + 52 [0x1d364a628]
│ + 3818 -[WKContentView(WKInteraction) _interpretKeyEvent:withContext:] (in WebKit) + 328 [0x1d3c55d6c]
│ + 3818 -[_UIKeyboardStateManager handleKeyTextCommandForCurrentEvent] (in UIKitCore) + 96 [0x1ba7ec264]
│ + 3818 -[UIApplication _currentKeyboardShortcutInvocationForKeyboardEvent:] (in UIKitCore) + 80 [0x1bb16dec4]
│ + 3818 -[UIResponder _keyboardShortcutInvocationForKeyboardEvent:] (in UIKitCore) + 592 [0x1bb17ce3c]
│ + 3818 -[UIResponder _enumerateKeyboardShortcutsInChainWithOptions:usingBlock:] (in UIKitCore) + 1268 [0x1bb17d99c]
│ + 3818 __59-[UIResponder _keyboardShortcutInvocationForKeyboardEvent:]_block_invoke_2 (in UIKitCore) + 216 [0x1bb17d280]
│ + 3818 __59-[UIResponder _keyboardShortcutInvocationForKeyboardEvent:]_block_invoke (in UIKitCore) + 76 [0x1bb17d0f4]
│ + 3818 -[UICommand _resolvedTargetFromFirstTarget:sender:] (in UIKitCore) + 128 [0x1bb39d8e4]
│ + 3818 -[WKWebView(WKViewInternalIOS) targetForAction:withSender:] (in WebKit) + 1640 [0x1d342f620]
│ + 3818 _UIResponderTargetForActionWithTestBlock (in UIKitCore) + 1684 [0x1ba8cbe50]
│ + 3818 _UIResponderTargetForActionWithTestBlock (in UIKitCore) + 1684 [0x1ba8cbe50]
│ + 3818 _UIResponderTargetForActionWithTestBlock (in UIKitCore) + 632 [0x1ba8cba34]
│ + 3818 _UIResponderCanPerformAction (in UIKitCore) + 80 [0x1ba8ccdec]
│ + 3818 ??? (in MarginNote 4) load address 0x100f38000 + 0x215f1c [0x10114df1c]
│ + 3818 ??? (in MarginNote 4) load address 0x100f38000 + 0xc0a7d8 [0x101b427d8]
│ + 3818 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] (in Foundation) + 212 [0x182e98b44]
│ + 3818 _CFRunLoopRunSpecificWithOptions (in CoreFoundation) + 532 [0x181721be0]
│ + 3818 __CFRunLoopRun (in CoreFoundation) + 924 [0x18164f54c]
│ + 3818 __CFRunLoopDoObservers (in CoreFoundation) + 648 [0x18164fea0]
│ + 3818 CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION (in CoreFoundation) + 36 [0x18164ffa4]
│ + 3818 ??? (in Gestures) load address 0x24c0f8000 + 0x25734 [0x24c11d734]
│ + 3818 ??? (in Gestures) load address 0x24c0f8000 + 0x25640 [0x24c11d640]
│ + 3818 ??? (in Gestures) load address 0x24c0f8000 + 0x26548 [0x24c11e548]
│ + 3818 ??? (in Gestures) load address 0x24c0f8000 + 0x657a4 [0x24c15d7a4]
│ + 3818 ??? (in Gestures) load address 0x24c0f8000 + 0x63a6c [0x24c15ba6c]
│ + 3818 ??? (in Gestures) load address 0x24c0f8000 + 0x32334 [0x24c12a334]
│ + 3818 ??? (in Gestures) load address 0x24c0f8000 + 0x10ec4 [0x24c108ec4]
│ + 3818 -[UIGestureRecognizer gestureNode:didUpdatePhase:] (in UIKitCore) + 308 [0x1bac8e900]
│ + 3818 -[UIGestureRecognizer _updateGestureForActiveEvents] (in UIKitCore) + 468 [0x1bac8ac80]
│ + 3818 _UIGestureRecognizerSendActions (in UIKitCore) + 272 [0x1b9f9aaa8]
│ + 3818 _UIGestureRecognizerSendTargetActions (in UIKitCore) + 96 [0x1b9f9acf4]
│ + 3818 -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] (in UIKitCore) + 124 [0x1b9f9ae80]
│ + 3818 -[UITextMultiTapRecognizer onStateUpdate:] (in UIKitCore) + 284 [0x1babb23ec]
│ + 3818 -[UIApplication sendAction:to:from:forEvent:] (in UIKitCore) + 100 [0x1b9fc2950]
│ + 3818 -[UITextSelectionInteraction _handleMultiTapGesture:] (in UIKitCore) + 928 [0x1bb3d7264]
│ + 3818 -[UITextSelectionInteraction _checkForRepeatedTap:gestureLocationOut:] (in UIKitCore) + 260
│ [0x1bb3d6484]
│ + 3818 -[UITextInteraction _beginSelectionChange] (in UIKitCore) + 140 [0x1bb3ce04c]
│ + 3818 -[WKContentView(WKInteraction) beginSelectionChange] (in WebKit) + 56 [0x1d3c51498]
│ + 3818 -[_UIKeyboardStateManager selectionWillChange:] (in UIKitCore) + 72 [0x1ba7db14c]
│ + 3818 -[_UIKeyboardStateManager prepareForSelectionChange] (in UIKitCore) + 140 [0x1ba7dae5c]
│ + 3818 -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] (in UIKitCore) + 164
│ [0x1baf55070]
│ + 3818 -[UIKeyboardTaskQueue lockWhenReadyForMainThread] (in UIKitCore) + 176
│ [0x1baf5480c]
│ + 3818 __42-[_UIKeyboardStateManager handleKeyEvent:]_block_invoke_3 (in UIKitCore) + 28
│ [0x1ba8095e0]
│ + 3818 -[UIKeyboardTaskQueue _lockWhenReadyForMainThread] (in UIKitCore) + 364
│ [0x1baf549b0]
│ + 3818 __126-[_UIKeyboardStateManager
│ _handleWebKeyEvent:withEventType:withInputString:withInputStringIgnoringModifiers:executionContext:]_block_invoke (in UIKitCore) + 76 [0x1ba8076d8]
│ + 3818 -[UIApplication(PrivateWebKit) _performDefaultBehaviorForEvent:] (in
│ UIKitCore) + 128 [0x1bb72b630]
│ + 3818 __31-[UINSApplicationDelegate init]_block_invoke_2 (in UIKitMacHelper) +
│ 72 [0x19f942f78]
│ + 3818 -[UINSInputView performDefaultBehaviorForEvent:] (in UIKitMacHelper) +
│ 108 [0x19f9684b0]
│ + 3818 -[NSApplication(UINSApplicationSwizzling) uinsSwizzledSendEvent:] (in
│ UIKitMacHelper) + 256 [0x19f950a38]
│ <exited with exit code 0>

│ SAMPLE_FILE=“/var/folders/51/y020gjv14kx9mpdqmw912t580000gn/T/copilot-tool-output-1778673590546-a97yzb.txt”
│ # Extract main thread call stack
│ grep -A 80 "Thread
.*Main Thread" “$SAMPLE_FILE” | head -80
└ 81 lines

● Check memory and heaviest stack info (shell)

│ Physical footprint: 731.3M
│ Physical footprint (peak): 1.5G
│ <exited with exit code 0>

│ SAMPLE_FILE=“/var/folders/51/y020gjv14kx9mpdqmw912t580000gn/T/copilot-tool-output-1778673590546-a97yzb.txt”
│ # Check memory and CPU context
│ grep -E “Physical footprint|CPU|Heaviest” “$SAMPLE_FILE” | head -10
└ 3 lines

◐ Now I can see the issue clearly! The main thread call stack shows a deadlock pattern:

  1. Main thread is handling a keyboard event (key press)

  2. It goes through WebKit::WebPageProxy::interpretKeyEvent_UIKeyboardStateManager handleKeyTextCommandForCurrentEvent

  3. In handling the key command, it calls _UIResponderCanPerformAction which triggers something in MarginNote’s code at offset 0x215f1c

  4. MarginNote’s code then calls [NSRunLoop(NSRunLoop) runMode:beforeDate:] - running a nested run loop synchronously on the main thread!

  5. This nested run loop triggers a gesture recognizer that initiates text selection, which then tries to wait for the keyboard state manager to finish its tasks

  6. But the keyboard state manager is already blocked, waiting for the nested run loop to complete - creating a circular dependency where each component is waiting on the other

The deadlock emerges from MarginNote’s canPerformAction check spawning a nested run loop that inadvertently blocks the keyboard handler that initiated it in the first place.

Beyond the deadlock, there’s a serious memory problem: the app is consuming 731MB of physical memory with a peak of 1.5GB, suggesting significant memory pressure that could be contributing to the overall instability. I should also revisit the
CloudKit sync behavior to see if that’s exacerbating things.

The root cause is clear now: MarginNote’s implementation of canPerformAction is invoking a nested run loop via runMode:beforeDate:, which creates a chain reaction. That nested loop triggers gesture recognizers and text selection
interactions that try to synchronize with the keyboard state manager, but the keyboard state manager is still blocked waiting for the original event handling to complete—creating a perfect deadlock scenario. This is a fundamental
architectural flaw in how MarginNote 4 handles action validation.

● 找到了!主线程发生了明确的死锁。

● Check thread count and CloudKit activity (shell)

│ 160
│ —
│ 3818 Thread_2266225: Main Thread DispatchQueue_
│ 3818 Thread_2266315: com.apple.NSEventThread
│ 3818 Thread_2266321: com.apple.uikit.eventfetch-thread
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266361: com.google.firebase.crashlytics.MachExceptionServer
│ 3818 Thread_2266401
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266402
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266403
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266404
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266405
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266406
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266407
│ + 3818 NSThread__start (in Foundation) + 732 [0x182e92a90]
│ 3818 Thread_2266408
│ <exited with exit code 0>

│ SAMPLE_FILE=“/var/folders/51/y020gjv14kx9mpdqmw912t580000gn/T/copilot-tool-output-1778673590546-a97yzb.txt”
│ # Check how many CloudKit ops and memory
│ grep -E “CloudKit|CKModify” “$SAMPLE_FILE” | wc -l
│ echo “—”
│ # Check other heavy threads
│ grep “Thread_” “$SAMPLE_FILE” | head -20
└ 23 lines

● 诊断结果:找到死锁根因 :red_circle:

主线程死锁调用链

键盘事件(按键/点击)
→ WebKit::WebPageProxy::interpretKeyEvent
→ UIKeyboardStateManager handleKeyTextCommandForCurrentEvent
→ UIResponder _keyboardShortcutInvocationForKeyboardEvent
→ WKWebView targetForAction:withSender:
→ _UIResponderCanPerformAction
:warning: MarginNote 4 自身代码 (offset 0x215f1c)
→ [NSRunLoop runMode:beforeDate:] ← 在主线程启动嵌套 RunLoop!
→ UITextMultiTapRecognizer 触发手势
→ UITextSelectionInteraction _beginSelectionChange
→ UIKeyboardTaskQueue waitUntilAllTasksAreFinished
:skull_and_crossbones: DEADLOCK:等待原始键盘事件完成
但原始键盘事件正被上面的嵌套 RunLoop 阻塞

问题本质

MarginNote 在 canPerformAction: 回调里(检查菜单是否可用时)调用了 [NSRunLoop runMode:beforeDate:] ——在主线程同步等待,这是典型的错误用法,导致死锁。

内存也在告警

┌──────────┬────────────┐
│ 指标 │ 当前值 │
├──────────┼────────────┤
│ 物理内存 │ 731 MB │
├──────────┼────────────┤
│ 历史峰值 │ 1.5 GB │
└──────────┴────────────┘


触发条件

卡住往往发生在:文本编辑区域内双击/三击选词,或输入快捷键时触发右键菜单检查。

建议

  1. 避免触发条件:在 MarginNote 文本区域内减少双击选词操作
  2. 强制停止恢复:kill -CONT 30236(如果卡住超过 30 秒)
  3. 上报 bug:这是 MarginNote
    4.3.2 的明确 bug,在 canPerformAction: 里不应该运行嵌套 RunLoop


和系统关系应该不大, 升级了好几次, 一直用的新版本系统, 每次打开软件, 就看一本书放后台一段时间后就会卡住, 只能重启app, 我不知道你们有没有出错log收集机制,如果需要我传log文件给你, 今天想起来用claude code分析下看有没有线索, 结果有些输出, 也可以参考下, 我之后一段时间想用这个软件, 希望能给个修复

Hello

你有没有同时打开WPS?建议把电脑进入安全模式,然后使用一段时间,这段时间不要打开其他的App。

Kind Regards,

Support Team

很巧, 我之前下了WPS但是一直没用过, 昨天刚打开过一次, 但是这个问题和WPS没有绝对的关联,更之前出问题时都没有下载WPS

| 建议把电脑进入安全模式,然后使用一段时间,这段时间不要打开其他的App。
这个步骤时干什么的? 能彻底解决问题吗, 如果你要我从哪里上传出错log我理解, 我电脑上几十个软件就这个软件软件总是卡死, 安全模式发挥了什么作用? 我也不知道怎么进入安全模式, 公司的电脑不方便随意尝试

Hello

安全模式可以尽可能避免后台进程的影响,所以才说不要启动其他的软件,目前出现你说的这种情况基本都是后台其他某个软件导致的,比如有用户当时的WPS版本会出现问题.

Kind Regards,

Support Team

谢谢答复, 这也是个方向, 我还想请教一些问题

  1. 你之前提到了WPS影响了后台进程, 你是怎么知道是这个软件的呢? 这个软件我是几年第一次使用, 之前使用marginnote4时也常卡住, 下次我怎么定位是什么软件再次产生干扰?
  2. 以你们的专业,mn4是不是不该这么容易被其他软件干扰的^ ^, 从没遇到其他软件有类似的情况, 目前有没有针对这一块的修复计划? 我其他的软件都是常见的合规软件, 按理说不应该那么容易干扰, 如果你们在修复中, 我可以上传log配合你们(假如有的话)

我给不少朋友推荐过这个软件, 很喜欢使用这个软件的一些设计, 希望这个问题能得到彻底的修复

Hello

因为跟你同情况的一个用户,他就是WPS导致的,后来换成dmg版的wps正常了.还有之前mos的影响导致其他问题.进程被其他软件占用了就容易这样子.你用的软件应该有些进程在后台常驻.

Kind Regards,

Support Team