2012-01-11 2 views
2

를 사용하는 동안 누출 : 나는 ARC를 사용하고이 프로젝트에서NSScanner scanUpToString 나는이 방법을 사용 URL의 쿼리 문자열의 일부를 분석하기 위해 ARC

NSScanner *scanner = [[NSScanner alloc] initWithString:query]; 
     [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]]; 

     NSString *parameterString = [NSString new]; 
     while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
     { 
      NSScanner *parameterScanner = [[NSScanner alloc] initWithString:parameterString]; 

      NSString *name = [NSString new]; 
      [parameterScanner scanUpToString:isEqual intoString:&name]; 

      NSString *value = [parameterString substringFromIndex:([name length] + 1)]; 
      [parameters setObject:value forKey:name]; 


     } 

을 만, 여전히 방법은이 라인에서 유출 :

[parameterScanner scanUpToString:isEqual intoString:&name]; 

정확히 누출이 무엇이며 어떻게 해결할 수 있습니까?

+1

계측기 누출 도구를 통해이 누출이 보입니까? 그런 경우 하단 패널로 이동하여 표시 옵션을 누수에서 사이클 및 루 트로 변경하여 새 유지주기 감지 도구를 표시합니다. 유지 보수주기가 ARC 하에서이 누출의 원인이되는지를 알 수 있습니다. 또한 Allocations 도구에서 힙 샷 기능을 사용하여 위 코드에 대해 각 패스에 대해 정확하게 누출 된 객체를 확인할 수 있습니다. –

+0

이름 변수가 누수되고, 위의 코드를 각각 넘깁니다. 어떤 솔루션을 어떻게 해결할 수 있습니까? – Thys

답변

1

당신이 생각하는 때 이름이 실제로 누출되지 않았는지 의심 name 변수

NSScanner *scanner = [[NSScanner alloc] initWithString:query]; 
    [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]]; 
    NSString *parameterString = [NSString new]; 
    while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
    { 
     NSScanner *parameterScanner = [[NSScanner alloc] initWithString:parameterString]; 

     NSString *name = nil; 
     [parameterScanner scanUpToString:isEqual intoString:&name]; 

     NSString *value = [parameterString substringFromIndex:([name length] + 1)]; 
     [parameters setObject:value forKey:name]; 


    } 
+0

이름을 초기화하지 않으면 여전히 새어 나옵니다. – Thys

6

이, 그것은 단순히 해제되지 않는 초기화 할 이유가 없다. ARC에서는 을 사용하는 방법과 비슷하게 scanUpToString:intoString:을 정의한다고 생각합니다. 즉, NSString * __autoreleasing *이 필요합니다. 따라서 전달 된 값은 실제로 자동 렌더링되고 현재 자동 복구 풀이 비워 질 때까지 해제되지 않습니다. 주위에 다른 점이 없다고 가정하면 실행 루프가 다시 돌아갈 때가됩니다. 그 메모리 사용이 당신에게 문제가 있다면, 루프의 주위에 명시 적 오토 릴리즈 풀을 배치 할 수있을 것이다, 그래서 개체가 즉시 사라 :

하지만 아마 필요가
NSScanner *scanner = [[NSScanner alloc] initWithString:query]; 
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]]; 

@autoreleasepool 
{ 
    NSString *parameterString = [NSString new]; 
    while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
    { 
     NSScanner *parameterScanner = [[NSScanner alloc] initWithString:parameterString]; 

     NSString *name = [NSString new]; 
     [parameterScanner scanUpToString:isEqual intoString:&name]; 

     NSString *value = [parameterString substringFromIndex:([name length] + 1)]; 
     [parameters setObject:value forKey:name]; 


    } 
} 

및 실행 루프는 취소됩니다 어쨌든 물체를 올리십시오.

즉, 컴파일러가 추가 임시 변수를 작성한다는 작은 문제가 있습니다. name 변수는 암시 적으로 __strong이므로 컴파일러에서 __autoreleasing 인 임시 변수를 삽입하고 주위 값을 복사합니다. NSString을 자동 리사이징으로 명시 적으로 선언하면이 문제를 피할 수 있습니다. 당신은 scanUpToString:intoString:이 당신을 위해 그것을하고 있기 때문에 당신은 또한 init을 필요로하지 않습니다. (이것은 왜 __autoreleasing이어야합니다). 자세한 내용은 http://developer.apple.com/library/mac/ipad/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html을 참조하십시오.

그래서, 전체 난 당신이 실제로 당신의 코드는 다음과 같이 할 생각 :

NSScanner *scanner = [[NSScanner alloc] initWithString:query]; 
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]]; 

NSString __autoreleasing *parameterString = nil; 
while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
{ 
    NSScanner *parameterScanner = [[NSScanner alloc] initWithString:parameterString]; 

    NSString __autoreleasing *name = nil; 
    [parameterScanner scanUpToString:isEqual intoString:&name]; 

    NSString *value = [parameterString substringFromIndex:([name length] + 1)]; 
    [parameters setObject:value forKey:name]; 
} 

희망하는 데 도움이!


또 다른 생각이 들었습니다. 아마도 name은 단순히 붉은 청어입니다. 누출은 할당이 발생한 위치를 표시하지만 parameters에 추가되면 name은이 루프를 넘어서 계속 존재합니다. 선택자에 따라 NSMutableDictionary 또는 그와 비슷한 것으로 추정됩니다. 내가 당신이라면 name 인스턴스가 유출되지 않았 음을 확인할 것입니다. 사전 (또는 사전에서 해당 키를 읽는 것이 누출 됨)이 유출되고 있기 때문입니다.

+0

그러나 이름이 새고 있지 않다면, 계기판에 누수가 표시된 이유는 무엇입니까? 위의 솔루션은 (장비에 의해 표시된) 누설을 해결하지 못했습니다. – Thys

+0

설명 할 수있는 또 다른 메모를 추가했습니다. 최적화가 여전히 유효하기 때문에 원본 텍스트도 그대로 두었습니다. – extremeboredom

0

자동 초기화 된 이니셜 라이저는 어떻게 사용합니까?

// [NSScanner scannerWithString:] 
// and 
// [NSString string] 

NSScanner *scanner = [NSScanner scannerWithString:query]; 
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]]; 

NSString *parameterString = [NSString string]; 
while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
{ 
    NSScanner *parameterScanner = [NSScanner scannerWithString:parameterString]; 

    NSString *name = [NSString string]; 
    [parameterScanner scanUpToString:isEqual intoString:&name]; 

    NSString *value = [parameterString substringFromIndex:([name length] + 1)]; 
    [parameters setObject:value forKey:name]; 
} 
+0

아니요, 이전 답변에서 말한 것과 같습니다. 자동 복구가 제대로 수행되지 않습니다. – Thys

4

나는 정확히 똑같은 문제를 다뤘다. 내 솔루션은 그것에 적용된 반복 횟수를 기반으로 NSScanner 객체를 재설정하는 것이 었습니다. 즉, 스캐너의 완성도 테스트가 실행될 때마다 값을 증가시킨 다음 해당 값을 기반으로 스캐너 객체를 다시 만들고 이전 스캐너의 현재 위치를 새 스캐너에 적용했습니다. 또한 새 버전의 스캐너를 만들 때마다 @autoreleasepool 표시가 있습니다.

내가이 방법으로 접근 한 이유는 NSScanner가 메모리 호그이기 때문에 루프에서 완료 될 때까지 해제되지 않기 때문입니다. 나는 액티비티 뷰어를 통해서만 검증했고 툴은 검증하지 않았다. (Mac OS X 응용 프로그램 설정에서 테스트했습니다)

즐기십시오!

NSUInteger currentLocation = 0; 
while (currentLocation < [dehyphenatedText length]) 
{ 
@autoreleasepool 
{ 
    NSUInteger iterations = 0; 
    NSScanner * scanner = [NSScanner scannerWithString:dehyphenatedText]; 
    [scanner setCharactersToBeSkipped: nil]; 
    [scanner setScanLocation: currentLocation]; 
    while (([scanner scanLocation] < [dehyphenatedText length]) && (iterations < 15000)) 
    { 
    NSString * found=nil; 
    [scanner scanCharactersFromSet:inverted intoString:&found]; 
    if ((found != nil) && ([found length] > 0)) 
    { 
       // Some code to process the results 
      } 
     found = nil; 
     if ([scanner scanLocation] < [dehyphenatedText length]) 
     { 
      [scanner scanCharactersFromSet: whiteSpaceAndMore intoString:nil]; 
     } 

     iterations ++; 
    } 
    } 
currentLocation = [scanner scanLocation]; 
}