objective-c – stringByAppendingString导致系统内存耗尽应用程
当我在“大”(37000行)文本文件上运行以下代码时,是否有人能指出我系统告诉我内存应用程序耗尽的方向?
-(void) writeToFile: (NSString*)filePath withSeparator:(NSString*) fieldSep{ NSString* completeFile = [[[NSString alloc] initWithString:@""] autorelease]; for(int i=0;i<[self numberOfRows];i++){ printf("im at line number... %i of %in",i,[self numberOfRows]); for(int j=0;j<[self numberOfColumns];j++){ completeFile = [completeFile stringByAppendingString:[self objectInRow:i column:j]]; if(j<[self numberOfColumns]-1){ //separator for all columns except last one completeFile = [completeFile stringByAppendingString:fieldSep]; } } completeFile = [completeFile stringByAppendingString:@"n"]; } NSError *error = nil; [completeFile writeToFile:filePath atomically:NO encoding:NSStringEncodingConversionAllowLossy error:&error]; if(error){ NSLog(@"Error writing file at %@n%@",filePath,[error localizedFailureReason]); } } 我出于调试原因添加了printf,前面似乎有4000行,然后它慢慢减速…我的文件包含超过37000行,类似于这些: 1893-11-6 136 194 165 解决方法
使用工厂方法分配对象时,会将对象添加到autoreleasepool.自动释放池仅在您的IBAction返回后运行事件循环时耗尽.
这里的技巧是将循环的内容放在自己的autorelasepool中. 但我们先解决最大的问题.你应该在这里使用一个NSMutableString类,这将大大减少你需要创建的对象的数量. 我们将completeFile切换为NSMutableString,使用工厂方法构造,然后附加到它: -(void) writeToFile: (NSString*)filePath withSeparator:(NSString*) fieldSep{ NSMutableString* completeFile = [NSMutableString string]; for(int i=0;i<[self numberOfRows];i++){ printf("im at line number... %i of %in",[self numberOfRows]); for(int j=0;j<[self numberOfColumns];j++){ [completeFile appendString:[self objectInRow:i column:j]]; if(j<[self numberOfColumns]-1){ //separator for all columns except last one completeFile appendString:fieldSep]; } } [completeFile appendString:@"n"]; } NSError *error = nil; [completeFile writeToFile:filePath atomically:NO encoding:NSStringEncodingConversionAllowLossy error:&error]; if(error){ NSLog(@"Error writing file at %@n%@",[error localizedFailureReason]); } } 但这留下了另一个问题.看到[self objectInRow:i column:j]?它(可能)仍然是一个自动释放的对象.那不会被清理干净. 我们可能已经使您的代码运行而不会崩溃,具体取决于数据的大小,但这是一个什么时候崩溃的问题. 要解决这个问题,我们需要引入自动释放池.我们每行和每列做一个.这可能看起来过多(事实上,在这种情况下,因为我们已经消除了外循环中的autoreleasepool使用),但自动释放池相当便宜.如果您正在对大量数据进行循环,那么这只是一种很好的做法. 您可以使用@autorelease块替换每个for块,例如: for(int i=0;i<[self numberOfRows];i++){ 附: for(int i=0;i<[self numberOfRows];i++) @autoreleasepool { 这给了我们这段代码: -(void) writeToFile: (NSString*)filePath withSeparator:(NSString*) fieldSep{ NSMutableString* completeFile = [NSMutableString string]; for(int i=0;i<[self numberOfRows];i++) @autoreleasepool { printf("im at line number... %i of %in",[self numberOfRows]); for(int j=0;j<[self numberOfColumns];j++) @autoreleasepool { [completeFile appendString:[self objectInRow:i column:j]]; if(j<[self numberOfColumns]-1){ //separator for all columns except last one completeFile appendString:fieldSep]; } } [completeFile appendString:@"n"]; } NSError *error = nil; [completeFile writeToFile:filePath atomically:NO encoding:NSStringEncodingConversionAllowLossy error:&error]; if(error){ NSLog(@"Error writing file at %@n%@",[error localizedFailureReason]); } } 不过最后一点.您在此处的错误检查不安全.未定义在成功时传入的错误指针会发生什么变化. [completeFile writeToFile:filePath atomically:NO encoding:NSStringEncodingConversionAllowLossy error:&error]; if(error){ NSLog(@"Error writing file at %@n%@",[error localizedFailureReason]); } 相反,你想要这个: BOOL ok = [completeFile writeToFile:filePath atomically:NO encoding:NSStringEncodingConversionAllowLossy error:&error]; if(!ok){ NSLog(@"Error writing file at %@n%@",[error localizedFailureReason]); } 那么,这应该做你想要的. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |