簡體   English   中英

如何解決NSFilehandle上的內存泄漏

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

我正在研究一個OS X應用程序,該應用程序始終運行並處理放置在他的隊列中的所有內容。 這些作業將其過程記錄在stdout中。 我正在嘗試通過在后台線程中運行的while循環實時從stdout中獲取此信息。 問題是,運行12小時后,內存使用量從25MB增加到750MB以上。 該應用程序正在使用ARC,所以我在這里有些迷路。 任何人有線索如何解決這個問題?

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

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

使用分配工具查看堆增長的原因。

特別是,您可以使用Heapshot分析非常有效地找出此類問題。

這是一篇文章。

簡而言之:

  • 在分配工具下啟動您的應用
  • (1)按標記堆按鈕
  • 等一會兒
  • 后藤(1)

重復一會兒。 對於您的情況,您可能希望每20分鍾到一個小時按一次標記堆按鈕。


傑里米(Jeremy)幾乎正確了。 您需要重新構建循環:

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

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

    readData = nil;
   } else {
    break;
   }
}

readData必須在池中。

ARC仍然在“幕后”使用引用計數。 特別是,它仍然使用自動釋放池,並且您無處不在消耗任何自動釋放池。 嘗試使用@autoreleasepool塊將while循環的主體@autoreleasepool

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

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

這相當於在循環開始時創建一個自動釋放池,並在循環結束時將其消耗掉。

編輯

正如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