gpt4 book ai didi

objective-c - stringByAppendingString 导致系统用完应用程序的内存

转载 作者:搜寻专家 更新时间:2023-10-30 19:52:29 25 4
gpt4 key购买 nike

当我在一个“大”(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 %i\n",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 返回后。

这里的技巧是将循环的内容放入它自己的自动释放池中。

但让我们先解决最大的问题。您应该在此处使用一个 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 %i\n",i,[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%@",
filePath, [error localizedFailureReason]);
}
}

不过,这会留下另一个问题。看到 [self objectInRow:i column:j] 了吗?它仍然(大概)是一个自动释放的对象。那不会被清理干净。

我们可能已经让您的代码运行而不会崩溃,这取决于数据的大小,但这是何时崩溃的问题,而不是如果崩溃。

为了解决这个问题,我们需要引入自动释放池。让我们每行每列做一个。这可能看起来过分(并且,事实上,在这种情况下是因为我们已经消除了在外循环中使用 autoreleasepool)但是 autoreleasepools 非常便宜。如果您要对大量数据进行循环,这是一种很好的做法。

您可以用 @autorelease block 替换每个 for block ,例如:

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 %i\n",i,[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%@",
filePath, [error localizedFailureReason]);
}
}

不过,最后一点。您在此处的错误检查不安全。未定义在成功 时像这样传入的错误指针会发生什么情况。

    [completeFile writeToFile:filePath atomically:NO
encoding:NSStringEncodingConversionAllowLossy error:&error];
if(error){
NSLog(@"Error writing file at %@\n%@",
filePath, [error localizedFailureReason]);
}

相反,你想要这样:

    BOOL ok = [completeFile writeToFile:filePath atomically:NO
encoding:NSStringEncodingConversionAllowLossy error:&error];
if(!ok){
NSLog(@"Error writing file at %@\n%@",
filePath, [error localizedFailureReason]);
}

那么,这应该做你想做的。

关于objective-c - stringByAppendingString 导致系统用完应用程序的内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20081690/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com