[英]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分析非常有效地找出此类问题。
简而言之:
重复一会儿。 对于您的情况,您可能希望每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.