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
相关产品推荐
相关产品推荐

