连续调用[NSPasteboard canReadObjectForClasses:options:]会导致内存膨胀

问题描述 投票:0回答:1

我正在使用以下简单的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一样。无论其他进程如何都会出现问题,因此运行程序几分钟就是观察交换文件创建所需的全部内容。

objective-c appkit nspasteboard
1个回答
0
投票

我想出了一个解决方案,使用[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;
}
© www.soinside.com 2019 - 2024. All rights reserved.