【问题标题】:NSStatusBar menu bar icon NSMenu leaking CFDataNSStatusBar 菜单栏图标 NSMenu 泄露 CFData
【发布时间】:2025-12-01 13:55:01
【问题描述】:

我有一个奇怪的数据泄漏,希望有人能解释这里出了什么问题。最小的工作示例项目如下:

  1. 创建一个新的 Objective-C macOS 项目 (Cocoa-App)。
  2. 删除除Info.plistmain.m 之外的所有内容
  3. Info.plist 中执行:
    • 删除条目Main nib file base name
    • Principal class 更改为“AppHook”。
    • 添加LSUIElement并将其设置为YES

接下来,将main.m 更改为:

#import <Cocoa/Cocoa.h>
#import "AppHook.h"

int main(int argc, const char * argv[]) {
    [[AppHook sharedApplication] run];
    return 0;
}

并添加这两个新文件:AppHook.h

#import <Cocoa/Coco a.h>

@interface AppHook : NSApplication <NSApplicationDelegate, NSMenuDelegate>
@property (strong) NSStatusItem *barItem;
@end

AppHook.m:

#import "AppHook.h"

@implementation AppHook
- (instancetype)init {
    self = [super init];
    self.delegate = self;
    return self;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    self.barItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength];
    self.barItem.highlightMode = YES;
    self.barItem.title = @"yep";
    self.barItem.menu = [[NSMenu alloc] initWithTitle:@"M"];
    self.barItem.menu.delegate = self;
    self.barItem.menu.autoenablesItems = NO;
}
- (NSInteger)numberOfItemsInMenu:(NSMenu*)menu {
    return 1;
}
- (BOOL)menu:(NSMenu*)menu updateItem:(NSMenuItem*)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel {
    item.title = [NSString stringWithFormat:@"%@", [NSDate date]];
    return YES;
}
@end

当使用 Instruments 和 Leaks 模板运行此应用程序时,我得到以下 CFData 泄漏:

0   Malloc      +1  1   00:03.319.300   AppKit  _DPSNextEvent
1   CFRetain    +1  2   00:03.319.303   AppKit  CopyCarbonUIElementAttributeValue
2   CFRelease   -1  1   00:03.319.310   AppKit  _DPSNextEvent

每次打开和关闭状态菜单时都会发生这种情况。所以反复点击菜单图标会造成大量泄漏。

这里没什么特别的,只是NSApplication 的一个子类(我需要覆盖sendEvent(_:))。

【问题讨论】:

  • 是否有sendEvent(_:) 的覆盖?或者这只是为了解释你为什么要继承NSApplication?这三个分配事件的回溯是什么?
  • 这只是为了解释我为什么要继承它。回溯没有帮助,指向[NSApplication run]。所有其他调用都是系统库,例如 -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
  • 我尝试了您的代码,但没有发现任何泄漏(macOS 10.13.6)。
  • 这里的操作系统版本相同。很奇怪。我已经删除了所有缓存和 DerivedData 文件夹,重新启动了我的 mac,其他所有操作都一样。如果不修改代码,泄漏就消失了。我会在接下来的几天里监控它。我猜这种泄漏出现在长时间使用 mac 后没有重新启动(正常运行时间)或者如果 xcode 打开很长时间(我的在后台运行了几个星期)

标签: objective-c macos memory-leaks nsmenu


【解决方案1】:

所以……经过相当长的一段时间后,它又发生了。

简答:

重新启动您的 Mac。

长答案:

如您所见,我的最新评论是近一个月前的事了。从那以后,我重新启动了我的 mac 两次,并且之前总是检查 Xcode Profiler。对于这两次重新启动,Profiler 没有显示任何泄漏。我不确定上次重启是什么时候,大约是两周前。今天我注意到 Profiler 再次出现同样的漏洞。

没有有什么作用:

  • 清理缓存和 DerivedData 文件夹。
  • 退出 Xcode 并重新启动它。
  • 两者兼而有之,也可任意组合。

似乎是 macOS 本身的一个错误。我会创建一个错误报告,但老实说,我什至不知道该写什么。再现性只是偶然:-/
此外,它不依赖于特定项目。将此示例项目作为参考,并在上个月保持不变。

【讨论】: