我正在使用以下简单的Objective-C程序从另一个进程接收消息并显示警报,使用NSPasteboard作为两个进程之间的通信方式。该程序适用于我,但我发现该程序正在消耗大量的RAM,无论合作伙伴进程是否向粘贴板发送新消息并且输入了内部警报块。它每隔几分钟就会在/private/var/vm/
生成1G交换文件,直到我杀死它为止。
我通过Xcode Instruments运行程序,我发现[NSPasteboard canReadObjectForClasses:options:]
每次调用时都会创建持久的__NSArrayI
对象,这是RAM膨胀的来源。其他人可以证实吗?这是[NSPasteboard canReadObjectForClasses:options:]
中的错误,还是我应该以不同方式执行此任务?
编辑:
我原本忘了启用ARC。即使启用了ARC,内存使用量的增长仍然大大超过了自动内存释放,并且交换文件仍在不断创建。有没有人有关于如何重写这个脚本以使用比while(true)
更好的约定的建议,以便[NSPasteboard canReadObjectForClasses:options:]
被称为更少?它仍然让我感到奇怪的是,这个AppKit函数不会自动释放它创建的__NSArrayI
对象,并假设ARC会处理它;这种图书馆的常见做法是什么?
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <AppKit/Appkit.h>
int main(void) {
NSPasteboard *pb = [NSPasteboard pasteboardWithName:@"alertBoard"];
NSArray *clsss = @[[NSString class]];
while(true) {
if ([pb canReadObjectForClasses:clsss options:nil]) {
NSArray *contents = [pb readObjectsForClasses:@[[NSString class]] options: nil];
CFStringRef msg = (__bridge CFStringRef) [contents firstObject];
[pb clearContents];
CFUserNotificationDisplayNotice(2, 3, NULL, NULL, NULL, CFSTR("Alert"), msg, NULL);
}
}
return 0;
}
我正在编译程序,就像g++ -framework Foundation -framework CoreFoundation -framework AppKit -fobjc-arc alertDaemon.m -o alertDaemon
一样。无论其他进程如何都会出现问题,因此运行程序几分钟就是观察交换文件创建所需的全部内容。
我想出了一个解决方案,使用[NSPasteboard changeCount]
检查是否已写入粘贴板而不是[NSPasteboard canReadObjectForClasses:options:]
。现在程序使用一致的少量内存而不是占用RAM。现在我只需要弄清楚如何使用更少的CPU周期,虽然比使用连续轮询检查NSPasteboard are scare更好的解决方案。
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#import <AppKit/Appkit.h>
int main(void) {
NSPasteboard *pb = [NSPasteboard pasteboardWithName:@"alertBoard"];
NSArray *clsss = @[[NSString class]];
int chngCnt = [pb changeCount];
while(true) {
if (chngCnt != [pb changeCount]) {
NSArray *contents = [pb readObjectsForClasses:@[[NSString class]] options: nil];
CFStringRef msg = (__bridge CFStringRef) [contents firstObject];
chngCnt = [pb clearContents];
CFUserNotificationDisplayNotice(2, 3, NULL, NULL, NULL, CFSTR("Alert"), msg, NULL);
}
}
return 0;
}