3

I am syncing around 5000 images from server in my iPad application.size of those images is around 2.5 GB and my iPad also have sufficient space.

But after syncing only 375 images my application start crashing with the following reason

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:

I am saving images in Document Directory using core data.

Please guide me if there is any restriction of saving data for application. And all this operation i am performing on main thread.

 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];

}

2 Answers2

4

You might need to use a Autorelease pool. According to the document, " if you write a loop that creates many temporary objects."

user523234
  • 14,323
  • 10
  • 62
  • 102
4

A couple of things:

  1. You seem to be recreating the array every time through the loop.
  2. It looks like you are creating a lot of autoreleased objects. Given that you may be creating a couple of thousand, you may want to wrap them in an @autoreleasepool block.
  3. There are several variables that you are recreating everytime through the loop which seem to be the same. Pull those out of the loop.
  4. Set the context's undo manager to nil. This will help reduce memory overhead.
  5. Finally, I'm not sure if you are doing this on the main thread or not, but dataWithContentsOfURL will block the main thread if you have a slow data connection. You may want to ensure that you are doing this off the main thread. That is a topic for another question though.
  6. You may want to use enumerateObjectsUsingBlock: rather than a for/loop. See here for why.

Try something along the lines of this:

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];
}];

Good Luck.

Community
  • 1
  • 1
timthetoolman
  • 4,613
  • 1
  • 22
  • 22