2011-06-29 28 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; 
}