簡體   English   中英

被 OS X 應用程序的 memory 泄漏所困擾

[英]Stumped on a memory leak for OS X app

好的,我有一個 memory 管理問題讓我陷入困境。 有一次我發誓這沒有問題,但現在它到處泄漏 memory 我不知道為什么。

首先,我啟動一個 NSTask,然后在任務運行時運行一個循環。

 NSTask *encodingTask = [[NSTask alloc] init];
            NSFileHandle *taskStdout = [NSFileHandle fileHandleForWritingAtPath:encodingOutput];
            [encodingTask setStandardOutput:taskStdout];
            [encodingTask setStandardError:taskStdout];
NSString argString = [NSString stingWithString: @"some arguments"];
[encodingTask setArguments:taskArgs];
            [encodingTask setLaunchPath:somePath];
            [encodingTask launch];

while ([encodingTask isRunning]){
                sleep(1);
                [self encodeProgressTimer];
            }

encodeProgessTimer 方法從 stdOut 中獲取最后一行並將其放在菜單欄中:

- (void)encodeProgressTimer
{
    if ([[NSUserDefaults standardUserDefaults] boolForKey:@"menuProgress"]) {
    // Read the last line
 NSString *fileData = [NSString stringWithContentsOfFile:encodingOutput encoding:NSASCIIStringEncoding error:nil];
    NSArray *lines = [fileData componentsSeparatedByString:@"\r"];
    NSString *lastLine = [lines objectAtIndex:[lines count] - 1];
    NSString *percent;
    NSString *eta;
    BOOL dataFound = NO;
    if ([lastLine length] == 71) {
        dataFound = YES;
        percentRange = (NSRange) {23,5};
        etaRange = (NSRange) {61,9};
        percent = [lastLine substringWithRange:percentRange];
        eta = [lastLine substringWithRange:etaRange];
    }
    else if ([lastLine length] == 72) {
        dataFound = YES;
        percentRange = (NSRange) {23,5};
        etaRange = (NSRange) {62,9};
        percent = [lastLine substringWithRange:percentRange];
        eta = [lastLine substringWithRange:etaRange];
    }
    else if ([lastLine length] == 70) {
        dataFound = YES;
        percentRange = (NSRange) {23,5};
        etaRange = (NSRange) {60,9};
        percent = [lastLine substringWithRange:percentRange];
        eta = [lastLine substringWithRange:etaRange];
    }

    if (dataFound) {
        NSMutableString *bottomStr = [[NSMutableString alloc] 
                                  initWithFormat:@"Encoding: %@%% - ETA %@", percent, eta];
                [appDelegate setMenuTop:topString andBottom:bottomStr];
        [bottomStr release];
    }

}

}

我的理解是,我沒有專門分配和初始化的任何東西都應該在方法完成后自動釋放,但事實並非如此。 調用此函數時,Memory 的使用率每秒呈指數增長。 如果我查看我的 memory 分配,生活 CFstings 的數量會激增。 如果我打開 encodeProgressTimer,我的問題 go 就會消失。 我嘗試向 encodeProgressTimer 添加一個自動釋放池,這使得 memory 的使用非常穩定,但是在運行 20 分鍾左右后,我得到了一個 EXC_BAD_ACCESS。 打開 Zombies 會變成:

*** -[NSConcreteAttributedString _drawCenteredVerticallyInRect:scrollable:]: message sent to deallocated instance 0x2bc756e0

我實際上經歷了並將每個變量聲明更改為它的 alloc/init 對應項並手動釋放它們,但這也沒有解決問題。 在這一點上,我很困惑。

同樣為了完整起見, [appDelegate setMenuTop: andBottom:] 方法如下所示:

-(void) setMenuTop: (NSString *) top andBottom: (NSString *) bottom
{  
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"menuProgress"]) {
    [statusItem setImage:nil];
    NSMutableParagraphStyle *lineHeight = [[NSMutableParagraphStyle alloc] init];
    [lineHeight setMaximumLineHeight:10.5];
    [lineHeight setLineBreakMode:NSLineBreakByTruncatingMiddle];
    OperationQueue *opQueue = [OperationQueue sharedQueue];
    NSString *sBuffer = [[NSMutableString alloc] initWithFormat: @"%@ (%i More)\n%@", top, [opQueue queueCount] - 1, bottom];
    attributes = [[NSDictionary alloc] initWithObjectsAndKeys:[NSFont menuFontOfSize:9], NSFontAttributeName, lineHeight, NSParagraphStyleAttributeName, nil];
    if (statusTitle)
        [statusTitle release];
    statusTitle = [[NSAttributedString alloc] initWithString: sBuffer  attributes: attributes];
    [statusItem setAttributedTitle: statusTitle];
    [lineHeight release];
    [sBuffer release];
    [attributes release];
    }

}

自動釋放池中會有很多東西,但是您需要明確地將其從 memory 排空到 go 。 更改您的while循環如下:

while ([encodingTask isRunning]){
   NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
   sleep(1);
   [self encodeProgressTimer];
   [pool drain];
}

其他東西:如果你在線程上運行它,你不能直接更新用戶界面項目。 您需要使用performSelectorOnMainThread:之類的東西來實際更新 UI。 如果您沒有在線程上運行它,則需要重新考慮您的設計。 循環運行時,應用程序的整個 UI 將凍結。

您可能想在此處使用屬性或取消引用。

if (statusTitle) {
        [statusTitle release];
        statusTitle = nil;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM