2011-09-15 25 views
1

可能重複:
Most memory efficient way to split an NSString in to substrings試圖分裂一個非常大的字符串

我試圖分裂一個20MB的字符串。我試過使用componentsSeparatedByString,但它消耗太多的RAM。我認爲這是由於它拆分了字符串,但也使原始字符串保持不變。這意味着該字符串會有效地存儲在內存中兩次(即使我在拆分之後立即釋放原始字符串仍然是個問題)。

我對Objective C非常陌生。我嘗試寫一些代碼將字符串添加到找到的字符串數組中時將字符串從原始字符串中移除。這個想法是,當發現字符串的可變數組變大時,原始字符串變小。唯一的問題是它泄漏內存和崩潰。如果有人能告訴我我做錯了什麼,那麼你會很棒!

NSRange range = [mainHtml rangeOfString:@"<p class=NumberedParagraph>"]; 
    int counter = 1; 

    // locations will == int max if it can't find any more occurances 
    while (range.location < [mainHtml length]) { 
     NSString *curStr; 
     NSRange curStrRange; 

     NSRange rangeToSearchIn = NSMakeRange(range.location+1, [mainHtml length] - range.location - 1); 
     NSRange nextRange = [mainHtml rangeOfString:@"<p class=NumberedParagraph>" options:NSCaseInsensitiveSearch range:rangeToSearchIn]; 

     if (nextRange.location > [mainHtml length]) 
     { 
      // This is the last string - get everything up to the end of the file 
      curStrRange = NSMakeRange(0, [mainHtml length]); 
      curStr = [mainHtml substringFromIndex:range.location]; 
     } else { 
      curStrRange = NSMakeRange(range.location, nextRange.location - range.location); 
      curStr = [mainHtml substringWithRange:curStrRange]; 
     } 

     // Remove the substring just processed from the orignal string 
     // * it crashes here, normally on the 3rd itteration 
     mainHtml = [mainHtml substringFromIndex:curStrRange.location + curStrRange.length]; 
     range = [mainHtml rangeOfString:@"<p class=NumberedParagraph>"]; 

     [self.parts addObject:curStr]; 
    } 
+0

'if(nextRange.location> [mainHtml length])'我不認爲這是正確的,不應該是'> ='? – jv42

+0

我對Objective C沒有把握,但是我知道在其他語言(C#)中,索引是基於0的,而長度不是這樣,所以最後一個字符會很長 - 1.我會發現。 – JoeS

回答

2

我認爲@babbidi有正確的想法。 mainHtml很大,你有許多自動發佈的副本(每個迭代一個副本),它們沒有被髮布。嘗試在代碼中添加以下@autorelease,以釋放每個循環結尾的所有自動釋放對象。如果您沒有使用Mac OS X 10.7,則只需在主循環外手動創建自動釋放池,並在每次迭代中將其耗盡一次。

NSRange range = [mainHtml rangeOfString:@"<p class=NumberedParagraph>"]; 
int counter = 1; 

// locations will == int max if it can't find any more occurances 
while (range.location < [mainHtml length]) { 
    @autorelease { 
     NSString *curStr; 
     NSRange curStrRange; 

     NSRange rangeToSearchIn = NSMakeRange(range.location+1, [mainHtml length] - range.location - 1); 
     NSRange nextRange = [mainHtml rangeOfString:@"<p class=NumberedParagraph>" options:NSCaseInsensitiveSearch range:rangeToSearchIn]; 

     if (nextRange.location > [mainHtml length]) 
     { 
      // This is the last string - get everything up to the end of the file 
      curStrRange = NSMakeRange(0, [mainHtml length]); 
      curStr = [mainHtml substringFromIndex:range.location]; 
     } else { 
      curStrRange = NSMakeRange(range.location, nextRange.location - range.location); 
      curStr = [mainHtml substringWithRange:curStrRange]; 
     } 

     // Remove the substring just processed from the orignal string 
     // * it crashes here, normally on the 3rd itteration 
     mainHtml = [mainHtml substringFromIndex:curStrRange.location + curStrRange.length]; 
     range = [mainHtml rangeOfString:@"<p class=NumberedParagraph>"]; 

     [self.parts addObject:curStr]; 
    } 
} 
+0

如果創建大量的小自動釋放對象,使用自動釋放池! – jv42

+0

自動釋放池解決了它!一個問題是它現在真的很慢。反對babbidi的答案我鏈接到一些C代碼也沒有泄漏,但非常緩慢。這是因爲我在分配newHtmlString時移動了20mb的數據,然後將其分配給現在發佈的htmlString?我能做些什麼嗎?謝謝,喬。 – JoeS

+0

@ user940516有些東西可以做到,不需要autorelease池,並且可以大大提高性能。不要複製mainHtml。相反,使用NSValue構建一個範圍數組,如果只在最後需要子字符串,則應使用範圍數組構建此數組。這應該至少需要大約40 MB的內存(給予或需要一點開銷)。 – aLevelOfIndirection

1

我不相信你有任何泄漏。 substringFromIndex:返回一個自動釋放字符串,所以它可能會保存在內存中多次迭代。您可以創建自己的substringFromIndex:方法(例如:createSubstringFromIndex),它將返回一個字符串保留字符串,您可以手動釋放。

+(NSString *)createSubstringFromIndex:(NSUInteger)index string:(NSString *)string{ 
    int newLen = [string length] - index; 
    if(newLen<=0) 
     return @""; // or nil 
    char *cStr = malloc(newLen+1); 
    for(int i=index; i<[string length]; i++){ 
     cStr[i-index]=[string characterAtIndex:i]; 
    } 
    cStr[newLen]='\0'; 
    NSString *retStr = [[NSString alloc] initWithCString:cStr encoding:NSASCIIStringEncoding]; 
    free(cStr); 
    return retStr; 
} 
在你的代碼

你不得不替換此:

mainHtml = [mainHtml substringFromIndex:curStrRange.location + curStrRange.length]; 

與此:

NSString *newHtmlString = [[self class] createSubstringFromIndex:curStrRange.location + curStrRange.length string:mainHtml]; 
[mainHtml release];    ///mainHtml should be retained before the while loop starts 
mainHtml = newHtmlString; 
+0

謝謝。你是第一個真正爲我提供代碼來解決問題的人,而不是抽象的「你可以做一些這樣的事情......」然後我必須嘗試編寫代碼。 – JoeS

+0

啊,它不起作用。它使用越來越多的RAM,然後在這一行上崩潰:NSString * retStr = [[NSString alloc] initWithCString:cStr encoding:NSASCIIStringEncoding]; – JoeS

+0

你在循環內發佈'mainHtml'嗎? –