2011-06-29 27 views
0

好的,我遇到了一個內存管理問題,它將我推上了一堵牆。有一次,我發誓這沒有問題,但現在它泄漏內存到處都是,我找不出原因。難以忍受OS X的內存泄漏應用程序

首先我開始一個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方法抓住從標準輸出的最後一行,並把在菜單欄:

- (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]; 
    } 

} 

}

這是我的理解是什麼,我沒有具體分配和初始化應該在方法完成時自動釋放,但事實並非如此。當被調用時,內存使用量每秒呈指數增長。如果我看看我的記憶分配,那麼活着的CFstings的數量將通過屋頂。如果我打開encodeProgressTimer,我的問題就會消失。我嘗試添加一個自動釋放池來編碼使內存使用非常穩定的ProgressTimer,但是在運行20分鐘左右後,我得到一個EXC_BAD_ACCESS。打開殭屍原來是成:

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

其實我去通過,並改變每個變量聲明爲它分配/初始化配對,並手動將其釋放,但它還是不解決問題。在這一點上,我很難過。

而且爲了完整起見,[的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]; 
    } 

}

回答

1

在autorelease池中會有大量的東西,但是你需要明確地將它耗盡以便內存消失。改變你的while循環,如下所示:

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

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

+0

這就是它!當我把NSAutoReleasePool放入並且仍然崩潰時,我認爲它仍然是一個內存管理問題。原來我還需要在主線程中運行狀態欄更新。現在一切似乎都順利運行,非常感謝! – Kris

0

你可能想在這裏使用性質或無出的參考。

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