2013-08-23 3 views
10

제가 작성한 프로세스 중에 내 애플리케이션이 메모리가 상승하고 있으며이를 공개하지 않는 것으로 보입니다.iOS [ARC] 앱이 메모리를 해제하지 않습니다.

내가 언급하고 싶은 첫번째 일은 내가 쓴 어떤의 기본 윤곽이 있다는 것이다 :
- (을 NSData -initWithContentsOfURL를 사용하여 데이터를 가져 오는) URL을 요청
- NSDictionarys의있는 NSArray에있는 NSData를 구문 분석 NSJSONSerialization + JSONObjectWithStream
사용 - 데이터로 FMDB 프레임 워크를 사용 SQLite는 데이터베이스의 레코드를 삭제/복호화 NSArray를 삽입/갱신을 통해 루프

애플리케이션

디코딩 된 상기 작업을 수행하지만 그것은 미결정 동안 루프를 수행 응용 프로그램이 "Loading"HUD를 표시하는 시간입니다. 나는이 프로세스를 얼마나 자주 수행하는지는 중요하지 않다고 생각하지만,이 프로세스를 제대로 수행하면 메모리 사용에 영향을주지 않아야한다는 것을 알았지 만, 언급할만한 가치가 있다고 생각했습니다. 내가 틀렸다면 조언 해주세요.

내 코드는 잘 작동하지만 의도 한대로 작동합니다. 그러나 응용 프로그램 코드를 프로파일 링 할 때 메모리가 계속 증가하는 것처럼 보입니다. 전반적으로 세그먼트가 감소하지만 전반적으로 계속 증가하고 있습니다 (IE는 이전에 사용 된 전체를 릴리스하지 않습니다).

이전에 설명한대로 할당, 누수, VM 추적기로 응용 프로그램의 프로파일을 작성하고 추적 주요 사항을 사용했습니다.

추적 하이라이트 : 메모리 사용량이 점차적으로 증가하지만 일부 (전체가 아님) 메모리가 떨어지는 것은 프로세스가 오래 실행되면 메모리가 많이 사용되어 종료된다는 것을 의미합니다.

할당 : 괜찮습니다. 할당은 급증하지만 항상 시작 지점으로 되돌아갑니다. 나는 heapshots했다 그리고 그들은 항상 (약 10 분 왼쪽) 세그먼트 당 최대 5백-7백킬로바이트

는 VM 추적기 떠나 드롭 다운 : 지속적으로 상승하는 메모리를 보여주고 증명을하고, 추적에서 발견으로 (전체 메모리를 해제하지 않습니다 하이라이트). 주민 정말 높게 보인다

누설 : 그것은 사실이 있음을 주목할 필요가
enter image description here enter image description here

: 여기

일부 할당/VM 트래커 실행의 스크린 샷의 응용 프로그램에서 발견 된 누수 없음 시도 :
- autoreleasepools 추가
- 각 속성을 할당하여 "강제로 해제"; NSURL, NSRequests 등과 같은 무기 호

내 질문 :
- 나는 메모리를 해제하기 위해 특별한 일을해야 하는가?
- 어떻게이 문제를 추가로 디버그 할 수 있습니까?
- 계측기에서 제공하는 데이터의 문제점을 가장 잘 찾아내는 방법은 무엇입니까?

---- 편집 : ----
가 여기에 데이터를 가져올 수있는 URL 요청을 전송하는 코드입니다.:

- (void) requestAndParse : (NSString *)url 
{ 
    NSURL *theURL; 
    ASIHTTPRequest *request; 
    NSData *collectedData; 
    NSError *error; 
    @try { 
        // File cache the NSData 
        theURL = [[NSURL alloc] initWithString: url]; 
        request = [ASIHTTPRequest requestWithURL: theURL]; 
        [request setDownloadDestinationPath: [[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingString:@"/cachefile.txt"]]; 
        [request startSynchronous]; 
        [request waitUntilFinished]; 

        collectedData = [[NSData alloc] initWithContentsOfFile:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingString:@"/cachefile.txt"]]; 


        if ([collectedData length] > 0) { 
         records = [NSJSONSerialization JSONObjectWithData:collectedData options:NSJSONReadingMutableContainers error:&error]; 
        } 

    } 
    @catch (NSException *exception) { 

        // Failed 
        NSLog(@"Parse error: %@", error); 

    } 
    @finally { 

        // DB updates with the records here 
        ... 

        // remove file 
        [[NSFileManager defaultManager] removeItemAtPath:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingString:@"/cachefile.txt"] error:nil]; 
        // release properties used 
        collectedData = nil; 
        request = nil; 
        theURL = nil; 
    } 

} 

위의 메서드는 응용 프로그램 대리자에서 while 루프 내에서 호출됩니다. while 루프는 앞에서 언급했듯이 미정의 길이입니다.

--- 편집 2 : ---

다음은 (FMDB를 사용하여 SQLite 데이터베이스를 업데이트)를 @finally 문 내에서 발생하는 것입니다. 내 수업에는 각 테이블마다 하나씩 많은 메소드가 있습니다.

-(BOOL) insertBatchOfRecords:(NSArray *)records { 

__block BOOL queueReturned = YES; 

@autoreleasepool { 

    FMDatabaseQueue *dbQueue = [self instantiateDatabaseQueue]; 
    [dbQueue inTransaction:^(FMDatabase *tdb, BOOL *rollback) { 
     if (![tdb open]) { 
      NSLog(@"Couldn't open DB inside Transaction"); 
      queueReturned = NO; 
      *rollback = YES; 
      return; 
     } 

     for (NSDictionary *record in records) { 
      [tdb executeUpdate:@"INSERT OR REPLACE INTO table (attr1, attr2) VALUES (?,?)", [record valueForKey:@"attr1"], [record valueForKey:@"attr2"]]; 

      if ([tdb hadError]) { 
       queueReturned = NO; 
       *rollback = YES; 
       NSLog(@"Failed to insert records because %@", [tdb lastErrorMessage]); 
       return; 
      } 
     } 
    }]; 

    [dbQueue close]; 
    dbQueue = nil; 

} 

return queueReturned; 
} 

을 그리고 다음에 -instantiateDatabaseQueue 방법 :

-(FMDatabaseQueue *) instantiateDatabaseQueue { 
@autoreleasepool { 
    return [FMDatabaseQueue databaseQueueWithPath: [self.getDocumentsDirectory stringByAppendingPathComponent:@"localdb.db"]]; 
} 
} 

autoreleasepools가 지저분 할 수 있지만, 코드들은 모두 처음부터 중복으로 그들은 모두, 그러나 동일한 패턴을 따른다 원래 이들을 가지고 있지 않았다. 개선이 있었는지 확인하기 위해 여러 위치에서 구현했습니다 (없었습니다).

--- EDIT 3 ---

나는 지난 몇 일 응용 프로그램을 프로파일 링, 여전히 답을 찾는 운이되지 않았다. 문제의 앱 부분을 별도의 프로젝트로 분리하여 실제로 메모리 사용을 유발하는지 확인했습니다. 이것은 앱이 여전히 똑같은 행동을하는 것처럼 정확함이 입증되었습니다.

사진을 더 찍어 본 결과, 실제로 무엇이 잘못되었는지 파악하는 데 어려움을 겪고 있습니다. 할당이 정상적으로 보입니다 (VM도 나에게 나쁘지 않습니까?), 아직 아무런 누수가 없습니다 (아무 것도 없으므로이 그림이 없습니다!)

그러나 Trace 하이라이트는 너무 많은 사용량 (3GS에서 약 70MB 이상)에 도달 할 때까지 메모리 사용량이 계속 올라간 다음 많은 양의 메모리를 사용하기 때문에 충돌합니다.

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

난 (아닌 파일로 저장)에있는 NSData 잡는위한 ASIHTTPRequest를 사용하여 문제를 감소시켰다. 위의 수정 된 코드를 참조하십시오. 그러나 문제는 여전히 지속됩니다. 질문, 원래 당으로

:
-이 응용 프로그램 프로세스의 두 번째 부분에 문제가 있습니까?

+1

+1 멋진 첫 번째 질문. 일부 코드를 포함해야 할 수도 있습니다. –

+2

새 할당이 실제로 무엇인지 확인하려면 스택 샷을 사용 했습니까? runloop에 실행할 기회를 주시겠습니까? 긴 루프를 더 작은 연산으로 분해하고 NSOperationQueue로 처리하는 것을 고려하십시오. – bneely

+0

URL 요청을 보내고 배열로 분해하는 실제 코드를 포함했습니다. – Joshua

답변

1

iOS에서 ARC를 사용하여 try/catch를 사용하면 메모리 누수가 발생할 수 있으므로 피해야합니다.

대체 접근법은 비동기 NSURLConnection 또는 NSURLConnection NSURLConnection을 사용하는 것입니다.

+0

매우 사실. 슬프지만 사실입니다. – Sulthan

+0

이 예제에서는 try/catch를 사용하여 누수를 일으키지 않습니다.이 문제는이 문제점을 발견 한 후에 try catch가 구현 된 것으로 확신합니다. 비동기 NSURLConnection도 사용되었지만 비동기가 끝날 때까지 주 스레드가 차단되어 동기식으로 변경되었습니다. Next 단계는 오늘하고있는 NSOperation 사용법을 확인하고 결과를 게시합니다. – Joshua

+0

그런 경우 requestAndParse 메소드가 누수를 일으키는 것이 확실합니까? – Ronan

관련 문제