代码之家  ›  专栏  ›  技术社区  ›  Alfonso Tesauro

在macOS Objective-C应用程序中,我需要以编程方式重新启动应用程序。这是可行的,但重新启动的应用程序内存泄漏为1Gb。有线索吗?

  •  0
  • Alfonso Tesauro  · 技术社区  · 3 年前

    我正在编写一个macOS Objective-C应用程序,它在启动时有一个登录屏幕。在设置中,有相应的“注销”功能。在这种情况下,我决定强制重新启动应用程序,这样我就不必报道新的情况,并使我更确信注销不会产生不必要的副作用。因此,我实施了我在网上找到的解决方案之一,具体如下:

    - (void)automaticallyRestartApp:(id)sender {
        Relaunch([[NSBundle mainBundle] bundleURL].path);
        dispatch_async( dispatch_get_main_queue(), ^{
            [NSApp terminate:self];
        });
    }
    

    重新启动功能为:

    static void Relaunch(NSString *destinationPath) {
    // The shell script waits until the original app process terminates.
    // This is done so that the relaunched app opens as the front-most app.
    int pid = [[NSProcessInfo processInfo] processIdentifier];
    
    // Command run just before running open /final/path
    NSString *preOpenCmd = @"";
    NSString *deletePrefsCmd = @"rm";
    
    NSString *wevpnPreferencesPath = [[[[[[NSProcessInfo processInfo] environment] objectForKey:@"HOME"] stringByAppendingPathComponent:@"Library"] stringByAppendingPathComponent:@"Preferences"] stringByAppendingPathComponent:@"com.vpn.osx.alfonso.plist"];
    
    NSString *quotedDestinationPath = ShellQuotedString(destinationPath);
    
    // OS X >=10.5:
    // Before we launch the new app, clear xattr:com.apple.quarantine to avoid
    // duplicate "scary file from the internet" dialog.
    if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
        // Add the -r flag on 10.6
        preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d -r com.apple.quarantine %@", quotedDestinationPath];
    }
    else {
        preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d com.apple.quarantine %@", quotedDestinationPath];
    }
    
    NSString *script = [NSString stringWithFormat:@"(while /bin/kill -0 %d >&/dev/null; do /bin/sleep 0.1; done; %@ %@; %@; /usr/bin/open %@) &", pid, deletePrefsCmd, ShellQuotedString(preferencesPath), preOpenCmd, quotedDestinationPath];
    
    [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
    }
    

    直到最近,我一直对这种实现感到高兴,因为我发现我的应用程序在重新启动时,内存使用率非常高,特别是当用户在输入凭据后单击登录时。内存占用保持1500Mb大约3秒钟,然后,当用户登录时,它会恢复正常。当用户第一次启动应用程序时,内存占用没有增加。首先,在某种意义上,我认为这是由于重新启动功能非常脏造成的。所以我在网上找到了这个 page ,其中相同的重新启动行为通过助手守护程序实现。我认为这看起来肯定更优雅,可以解决这个问题,但不幸的是,同样的情况也发生了。登录时自动重新启动时占用大量内存。 我的应用程序已经使用了一个守护进程,所以我在XPC与守护进程的通信中添加了一个方法。这是我对XPC协议中相关方法的实现:

    - (void)askServiceToRelaunchHostAppAtPath:(NSString *)hostAppPath withReply:(void     (^)(BOOL))reply {
    
        self.relaunchHostAppExecutablePath = hostAppPath;
    
        self.shouldRelaunchHostAppOnNextHostAppQuit = YES;
    
        reply(YES);
    }
    

    然后,在主机应用退出时调用的守护进程的方法中,有:

    if (self.shouldRelaunchHostAppOnNextHostAppQuit) {
        self.shouldRelaunchHostAppOnNextHostAppQuit = NO;
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSError *error;
    
           NSRunningApplication __unused *relaunchedHostApp = [[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:self.relaunchHostAppExecutablePath] options:0 configuration:@{} error:&error];
            
            self.relaunchHostAppExecutablePath = nil;
        });
        
    }
    

    如上所述,这种完全不同的方法得到了完全相同的坏记忆结果。你会读到守护程序代码,我试图让守护程序在重新启动应用程序之前等待25秒。不幸的是,这也无济于事。任何可能的建议都将不胜感激。谢谢你的关注。

    0 回复  |  直到 3 年前