2011-03-24 3 views
1

지도에서 일부 타일을 표시하는 iPhone 앱을 개발 중입니다. 타일을 인터넷이나 파일 시스템에서로드하는 스레드가 있습니다. 이것은iPhone 메모리 충돌 : 신호 0

내 생각이 무단 쓰레드에서 타일로로드된다는 것이다 .. 메모리 부족이 IM 수단 신호를 0으로 많은 타일을 응용 chrashes를 표시 한 후 무단 스레드에게

while(true){ //get tile into cache }

Unfortunateley 인

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
while(true){ 
    UIImage * img = nil; 
    NSFileHandle * tile = [NSFileHandle fileHandleForReadingAtPath:filePath]; 
    if(tile){ 
     NSData * data = [tile readDataToEndOfFile]; 
     if(data){ 
      img = [[UIImage alloc] initWithData:data]; 
      local = YES; 
     } 
    } 
    if(img == nil){ 
     NSURL * url = [NSURL URLWithString: [NSString stringWithFormat:@"http://tile.openstreetmap.org/%@.png", todoKey ] ]; 
     img = [[UIImage alloc] initWithData: [NSData dataWithContentsOfURL: url options:NSDataReadingMapped error:&error] ]; 
    } 

    if(img != nil){ 
     [cache addObject:img]; //cache is an array of tiles 
    } 

    [img release]; 
    [self cleanupCache]; //method to check if cache is full, and if so remove's objects from it 
} 
[pool release]; 

임은 autoreleasep 생각 : 오토 릴리즈, 그리고 ..

는 기본적으로 내 끝없는 스레드에서이 일을 메신저 오토 릴리즈 노된다 ool은 "죽은"참조를 수시로 정리하지 않으며, 모든 타일은 메모리에 보관됩니다. 악기 누설을 검사 할 때 메모리 누수가 없지만 '라이브 메모리'가 계속 누적됩니다.

왜 이런 일이 발생하고 그것을 막을 수있는가?

+0

왜 무한 루프가 필요합니까? – MCannon

+0

내 루프가 요청하면이 루프에서 요청 타일을 다운로드합니다. '이 타일을 가지고 있습니까?'스레드가이를 다운로드하여 캐시에 저장합니다. – Nick

답변

2

당신은 프로그램의 첫 번째 두 라인을 교체해야합니다

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
while(true){ 
    ... 
    [pool release]; 
} 

는 현재

while(true){ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    ... 
    [pool release]; 
} 

해야한다, 당신의 루프를 처음 여행 후, 생성 한 NSAutoreleasePool이 해제됩니다. 이 후에 모든 자동 회수 된 객체는 호출 스택의 다른 NSAutoreleasePool에 추가됩니다. 나는 프로그램이 실행되는 동안이 부모 autorelease 풀이 결코 풀어지지 않는다고 의심한다.

+0

대답 주셔서 감사합니다, NSURLCache .. 내가 여기에 해결책을 찾았습니다 : http://www.iphonedevsdk.com/forum/iphone-sdk-development/52972-cfdata-memory -problem.html – Nick

0
if(img != nil){ 
[cache addObject:img]; 

cache에는 추가 한 모든 개체에 대한 참조가 여전히 있습니다. 아마 사용하지 않을 객체를 제거해야합니다.

+0

감사합니다. Praveen,하지만 이미 감사했습니다. 각 다운로드 작업 후 캐시가 꽉 찼는 지 (객체의 x 양) 확인합니다. 그렇다면 캐시를 정리하고 [cache removeObjectAtIndex : i]를 호출하여 제거하십시오. – Nick

+0

Ok 변수 타일은 어때? –

+0

자동 실행 된 객체 : NSFileHandle * tile = [NSFileHandle gileHandleForReadingAtPath : filePath]; – Nick

0

코드에서 들여 쓰기를 수정 했으므로 제대로 작성했으면합니다. 향상된 들여 쓰기는 한 가지 문제점을 분명하게합니다.

이미 출시 된 개체 인 풀을 릴리스합니다.

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];을 루프 내부로 이동하십시오.

하지만 가장 먼저 루프를 제거해야합니다.

또 다른 문제는 img를 nil로 설정하지 않는다는 것입니다. 루프의 첫 번째 실행에 유효한 img이있는 경우 코드는 이후의 다른 모든 루프 실행에 대해 유효하다고 생각합니다. 캐시에서 어딘가에 img를 제거하면 img이 가리키는 객체가 해제되어 할당 해제됩니다. 캐시에 추가하려고하면 할당 해제 된 객체에 retain이 전송됩니다.

루프 시작 부분에 img = nil;을 추가하십시오.

+0

히야, 그것을 고쳐 주셔서 감사합니다 ..하지만 한 가지는 잘못되었습니다 .. [풀 릴리스] 동안 (사실) 루프 (실제로) 루프 밖에서 발생합니다 ... 당신은 루프,하지만 내 견해가 묻는다면이 스레드의 의미는 요청에 따라 타일을 다운로드합니다. '이 타일을 가지고 있습니까?'스레드는 다운로드하여 캐시에 넣습니다. 맨 위에 내 루프, 후에 (사실), UIImage * img = nil 넣어,이 이미지는 루프에 있습니다 ..하지만 여전히 내 문제를 해결하지 않습니다 .. – Nick