3

我在我的 iPad 应用程序中从服务器同步大约 5000 张图像。这些图像的大小约为 2.5 GB,我的 iPad 也有足够的空间。

但是在仅同步 375 张图像后,我的应用程序开始崩溃,原因如下

malloc: *** mmap(size=1048576) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

2013-02-14 06:20:50.058 AAA[1250:907] ***

Terminating app due to uncaught exception 'NSMallocException',
 reason: 'Attempt to allocate 1048576 bytes for NS/CFData failed'

*** First throw call stack:

我正在使用核心数据将图像保存在文档目录中。

如果有任何保存应用程序数据的限制,请指导我。我在主线程上执行的所有这些操作。

 for (int i = 0; i < [shadowElement3 count]; i++)
        {
            NSMutableArray* array = [[NSMutableArray alloc] init];
            Product* failedBankInfo = [NSEntityDescription insertNewObjectForEntityForName:@"Product"                                                                    inManagedObjectContext:context];

            NSXMLElement* element11    = [shadowElement3 objectAtIndex:i];
            NSString* strPath = [element11 stringValueForNode:@"B1_COD"];

            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
            NSString *documentsDirectory = [paths objectAtIndex:0];
            NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:strPath];

            NSLog(@"%@",[element11 stringValueForNode:@"img"]);
            NSData* receivedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:              [element11 stringValueForNode:@"img"]]];
            [receivedData writeToFile:savedImagePath atomically:YES];

            [array addObject:savedImagePath];

}

4

2 回答 2

4

有几件事:

  1. 您似乎每次通过循环都在重新创建数组。
  2. 看起来您正在创建很多自动释放的对象。鉴于您可能要创建几千个,您可能希望将它们包装在 @autoreleasepool 块中。
  3. 您每次通过循环重新创建的几个变量似乎是相同的。将它们拉出循环。
  4. 将上下文的撤消管理器设置为零。这将有助于减少内存开销。
  5. 最后,我不确定您是否在主线程上执行此操作,但如果您的数据连接速度较慢, dataWithContentsOfURL 会阻塞主线程。您可能希望确保您在主线程之外执行此操作。这是另一个问题的主题。
  6. 您可能想要使用enumerateObjectsUsingBlock:而不是 for/loop。请参阅此处了解原因。

尝试这样的事情:

NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:[shadowElement3 count]];
NSXMLElement* element11;
NSString* strPath;
NSString *savedImagePath;
Product* failedBankInfo;

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

[context setUndoManager:nil];

for (int i = 0; i < [shadowElement3 count]; i++)
{

   @autoreleasepool{
      failedBankInfo = [NSEntityDescription insertNewObjectForEntityForName:@"Product"                                                                    inManagedObjectContext:context];
      element11 = [shadowElement3 objectAtIndex:i];
      strPath = [element11 stringValueForNode:@"B1_COD"];
      savedImagePath= [documentsDirectory stringByAppendingPathComponent:strPath];

      NSData* receivedData = [NSData dataWithContentsOfURL:[NSURL URLWithString:                       [element11 stringValueForNode:@"img"]]];
      [receivedData writeToFile:savedImagePath atomically:YES];
      [array addObject:savedImagePath];

      // you don't seem to be doing anything with the Managed Object you created,
      // I assume you are saving the path.  So do so and batch save the context.
      // This will help free up memory.
      failedBankInfo.pathName = savedImagePath;
      if ( i % 100 ==0 ){
          NSError *error;
          [context performBlock:^{

             [context save:&error];
             // handle error

             // reset the context cause you don't seem to be doing anything else
             // with the objects.  This will free up memory
             [context reset];
          }];
      }
  }

}

// One last save
NSError *error;
[context performBlock:^{
    [context save:&error];
    // handle error is exercise for the reader.

    // reset the context cause you don't seem to be doing anything else
    // with the objects.  This will free up memory
    [context reset];
}];

祝你好运。

于 2013-02-14T06:25:49.480 回答
4

您可能需要使用自动释放。根据该文件,“如果您编写一个创建许多临时对象的循环。”

于 2013-02-14T05:57:42.360 回答