You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cocoa中addGlobalMonitorForEventsMatchingMask内存泄漏问题排查

问题描述

使用Cocoa的addGlobalMonitorForEventsMatchingMask:时遇到内存泄漏:随时间推移,鼠标按下/松开等事件会导致NSEvent对象无法释放,内存持续增长;但按键事件无此问题。项目未使用ARC,需手动管理内存。

相关代码如下:

AppDelegate.h

#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>

@interface AppDelegate : NSObject <NSApplicationDelegate, NSUserNotificationCenterDelegate> {
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;

@end

AppDelegate.m

#import "AppDelegate.h"

const unsigned long long FLAGS = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged | NSEventMaskLeftMouseDown | 
                                 NSEventMaskLeftMouseUp | NSEventMaskRightMouseDown | NSEventMaskRightMouseUp | 
                                 NSEventMaskOtherMouseDown | NSEventMaskOtherMouseUp;

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
  [NSEvent addGlobalMonitorForEventsMatchingMask:FLAGS handler:^(NSEvent *event){
    //NSLog(@"event");
  }];
}

@end

main.m

#include "AppDelegate.h"
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    AppDelegate *delegate = [[AppDelegate alloc] init];

    NSApplication *application = [NSApplication sharedApplication];
    [application setDelegate:delegate];
    [application setActivationPolicy:NSApplicationActivationPolicyAccessory];
    [application run];
  }
  return 0;
}

编译命令:

gcc -framework Cocoa -framework IOKit -o testleak main.m AppDelegate.m

已尝试多种NSAutoreleasePool组合但未解决,Zombie工具显示NSEvent对象数量持续增加。

原因分析

  • 线程差异导致自动释放池缺失:全局事件监视器的handler block并非始终在主线程执行——按键事件通常在主线程处理,主线程的@autoreleasepool可以自动释放NSEvent;但鼠标事件会在后台线程触发,MRC模式下后台线程没有默认的自动释放池,导致NSEvent对象无法被自动释放,积累成内存泄漏。
  • MRC内存管理规则限制:在MRC中,所有自动释放的对象必须依赖当前线程的自动释放池才能被回收,后台线程无默认池时,对象会一直驻留在内存中。

解决方案

在handler block内部手动添加@autoreleasepool,确保后台线程中的NSEvent能被正确释放:

修改后的AppDelegate.m关键代码:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
  [NSEvent addGlobalMonitorForEventsMatchingMask:FLAGS handler:^(NSEvent *event){
    @autoreleasepool {
      // NSLog(@"event");
      // 其他事件处理逻辑
    }
  }];
}

此外,需确保编译时确实处于MRC模式(未启用ARC),若项目存在混合ARC的情况,需为相关文件添加-fno-objc-arc编译标记。


内容的提问来源于stack exchange,提问作者Federico Terzi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:48:11