2013-07-16 3 views
1

나는 항상 실행되고 그의 큐에있는 모든 것을 처리하는 OS X 응용 프로그램을 만들고 있습니다. 이 작업은 프로세스를 표준 출력에 기록합니다. 백그라운드 스레드에서 실행되는 while 루프를 사용하여이 정보를 표준 출력에서 ​​실시간으로 가져 오려고합니다. 문제는 12 시간이 지난 후 메모리 사용량이 25MB에서 750MB 이상으로 증가한 것입니다. 응용 프로그램은 ARC를 사용하므로 여기서 약간 잃어 버렸습니다. 누구든지 어떤 단서를 해결하는 방법? NSFilehandle에서 메모리 누출 문제를 해결하는 방법

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]; 
    } 
} 
+1

당신이 사용하는 엑스 코드를 시도해 봤어을 누수를 탐지하는 도구? – Fonix

+0

예 내가 한 일과 이것이 끝난 곳입니다. 나는 며칠 동안 붙어서 다른 모든 것을 시도했다. –

답변

3

는 힙이 증가하는 이유를 확인하기 위해 할당 악기를 사용합니다.

특히 힙샷 분석을 사용하면 이러한 문제를 매우 효율적으로 파악할 수 있습니다. 한마디로

Here is a write-up.

:

  • 시작합니다 할당 악기
  • (1)을 눌러 마크 힙 버튼
  • 대기 잠시
  • 고토 (1 아래의 앱)

잠시 동안 반복하십시오. 귀하의 경우, 마크 힙 버튼을 20 분에서 1 시간 간격으로 한 번씩 눌러야 할 수 있습니다.


제레미가 거의 옳았습니다. 당신은 당신의 루프 비트를 재구성해야합니다

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

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

    readData = nil; 
    } else { 
    break; 
    } 
} 

readData 풀에 있어야합니다.

+0

위대한, 나는 그것을 시험해 볼 것이다. –

+0

내가 말했듯이 문제는이 문장에있는 것 같다. while ((readData = [fileStd availableData]) && [readData length]) {} 하지만 왜 아직도 찾을 수 없는가? 아웃. –

+0

그래, 루프의 약간의 재구성은 트릭을했다. 감사! –

3

ARC는 여전히 "Under the Hood"라는 참조 카운트를 사용합니다. 특히 autorelease pool을 사용하고 autorelease pool을 배수하지 않습니다. 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]; 
     } 
    } 
} 
+0

while 루프 주위에서 autoreleasepool로 시도했지만 작동하지 않았습니다. 그리고 당신의 방법도 효과가 없었습니다. 메모리는 여전히 분당 1MB로 올라갑니다. –

+3

'readData'는 메모리 증가의 원인입니다. 주기적으로 플러시되는 autorelease 풀에 있어야합니다. 루프 외부의 자동 릴리스 풀은 도움이되지 않으며 루프 내부의 하나는 작성된 것처럼 도움이되지 않습니다. – bbum

+0

@bbum 좋은 장소, 다른 것을 시도해 보겠습니다. – JeremyP

관련 문제