简体   繁体   English

如何解决NSFilehandle上的内存泄漏

[英]How to solve a memory leak on a NSFilehandle

I'm working on an OS X app which runs all the time and handles everything placed in his queue. 我正在研究一个OS X应用程序,该应用程序始终运行并处理放置在他的队列中的所有内容。 These jobs log their process in stdout. 这些作业将其过程记录在stdout中。 I'm trying to get this info out of stdout realtime with a while loop which runs in a background thread. 我正在尝试通过在后台线程中运行的while循环实时从stdout中获取此信息。 Problem is that after running 12 hours the memory usage went up from 25MB to >750MB. 问题是,运行12小时后,内存使用量从25MB增加到750MB以上。 The app is using ARC so I'm a little lost here. 该应用程序正在使用ARC,所以我在这里有些迷路。 Anyone any clue how to solve this? 任何人有线索如何解决这个问题?

NSFileHandle *fileStd = [stdPipe fileHandleForReading];

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: cmd];
[task setArguments: arguments];

NSPipe *stdPipe = [NSPipe pipe];
NSPipe *errPipe = [NSPipe pipe];

[task setStandardOutput: stdPipe];
[task setStandardError: errPipe];

NSFileHandle *fileStd = [stdPipe fileHandleForReading];

[task launch];

NSData *readData;
NSString *logString;

while ((readData = [fileStd availableData]) && [readData length]){

   logString = [[NSString alloc] initWithData: readData encoding: NSUTF8StringEncoding];
        [self parseLog:logString];
    }

    readData = nil;
}

[task waitUntilExit];

And the parseLog method: 和parseLog方法:

+ (void) parseLog:(NSString *)output {

    NSArray *chunks = [output componentsSeparatedByString: @"\r"];
    NSString *lastLine = [chunks lastObject];

    [lastLine writeToFile:@"/tmp/status.log" atomically:YES encoding:NSUTF8StringEncoding error:nil];

    NSRange textRange = [lastLine rangeOfString:@"<TEST> "];
    if(textRange.location != NSNotFound) {

        NSMutableDictionary *info = [NSMutableDictionary dictionary];
        [info setObject:lastLine forKey:@"test"];

        [[NSNotificationCenter defaultCenter] postNotificationName:@"handleNotification" object:nil userInfo:info];
    }
}

Use the Allocations Instrument to see why your heap is growing. 使用分配工具查看堆增长的原因。

In particular, you can use Heapshot analysis to figure out problems like these quite efficiently. 特别是,您可以使用Heapshot分析非常有效地找出此类问题。

Here is a write-up. 这是一篇文章。

In short: 简而言之:

  • launch your app under the Allocations Instrument 在分配工具下启动您的应用
  • (1) press the mark heap button (1)按标记堆按钮
  • wait a while 等一会儿
  • goto (1) 后藤(1)

Repeat that for a while. 重复一会儿。 In your case, you might want to press the mark heap button once every 20 minutes to an hour. 对于您的情况,您可能希望每20分钟到一个小时按一次标记堆按钮。


Jeremy almost got it right. 杰里米(Jeremy)几乎正确了。 You need to restructure your loop a bit: 您需要重新构建循环:

while (1) {
@autoreleasepool {
   if (readData = [fileStd availableData]) && [readData length]){

   logString = [[NSString alloc] initWithData: readData encoding: NSUTF8StringEncoding];
        [self parseLog:logString];
    }

    readData = nil;
   } else {
    break;
   }
}

readData needs to be in the pool. readData必须在池中。

ARC still uses reference counting "under the hood". ARC仍然在“幕后”使用引用计数。 In particular, it still uses autorelease pools and you nowhere drain any autorelease pools. 特别是,它仍然使用自动释放池,并且您无处不在消耗任何自动释放池。 Try enclosing the body of your while loop with an @autoreleasepool block. 尝试使用@autoreleasepool块将while循环的主体@autoreleasepool

while ((readData = [fileStd availableData]) && [readData length]){
    @autoreleasepool
    {

       logString = [[NSString alloc] initWithData: readData encoding: NSUTF8StringEncoding];
       [self parseLog:logString];
    }
}

That's the modern equivalent of creating an autorelease pool at the start of the loop and draining it at the end. 这相当于在循环开始时创建一个自动释放池,并在循环结束时将其消耗掉。

EDIT 编辑

As bbum said, readData is put in an autorelease pool on each iteration but it's outside the @autoreleasepool bit, so the code will need restructuring: 正如bbum所说,readData在每次迭代时都放入一个自动释放池中,但是它位于@autoreleasepool位之外,因此代码需要进行重组:

bool dataToProcess = true;
while (dataToProcess){
    @autoreleasepool
    {
       NSData* readData = [fileStd availableData];
       dataToProcess = [readData length] > 0;
       if (dataToProcess)
       {
           logString = [[NSString alloc] initWithData: readData encoding: NSUTF8StringEncoding];
           [self parseLog:logString];
       }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM