[英]Stumped on a memory leak for OS X app
好的,我有一個 memory 管理問題讓我陷入困境。 有一次我發誓這沒有問題,但現在它到處泄漏 memory 我不知道為什么。
首先,我啟動一個 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 方法從 stdOut 中獲取最后一行並將其放在菜單欄中:
- (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];
}
}
}
我的理解是,我沒有專門分配和初始化的任何東西都應該在方法完成后自動釋放,但事實並非如此。 調用此函數時,Memory 的使用率每秒呈指數增長。 如果我查看我的 memory 分配,生活 CFstings 的數量會激增。 如果我打開 encodeProgressTimer,我的問題 go 就會消失。 我嘗試向 encodeProgressTimer 添加一個自動釋放池,這使得 memory 的使用非常穩定,但是在運行 20 分鍾左右后,我得到了一個 EXC_BAD_ACCESS。 打開 Zombies 會變成:
*** -[NSConcreteAttributedString _drawCenteredVerticallyInRect:scrollable:]: message sent to deallocated instance 0x2bc756e0
我實際上經歷了並將每個變量聲明更改為它的 alloc/init 對應項並手動釋放它們,但這也沒有解決問題。 在這一點上,我很困惑。
同樣為了完整起見, [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];
}
}
自動釋放池中會有很多東西,但是您需要明確地將其從 memory 排空到 go 。 更改您的while循環如下:
while ([encodingTask isRunning]){
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
sleep(1);
[self encodeProgressTimer];
[pool drain];
}
其他東西:如果你在線程上運行它,你不能直接更新用戶界面項目。 您需要使用performSelectorOnMainThread:
之類的東西來實際更新 UI。 如果您沒有在線程上運行它,則需要重新考慮您的設計。 循環運行時,應用程序的整個 UI 將凍結。
您可能想在此處使用屬性或取消引用。
if (statusTitle) {
[statusTitle release];
statusTitle = nil;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.