Domanda

I have the current code to let a big list of files (about 6k images, about 2.8GB in size) for our Enterprise App.

At about 1.71GB transferred files (~660seconds) the memory obviously was depleted. I wonder what I can do to optimize:

Queue:

dispatch_queue_t imageQueue1 = dispatch_queue_create("Image Queue 1", NULL);

Loop:

for (int i = 0; i < [imgs count]; i++) {
    dispatch_async(imageQueue1, ^{
        NSString *path = [[NSString alloc] initWithFormat:@"%@/%@", damPath, [imgs objectAtIndex:i]];
        NSURL *url = [[NSURL alloc] initWithString:path];
        NSData *data = [[NSData alloc] initWithContentsOfURL:url];

        NSString *savePath = [[NSString alloc] initWithFormat:@"%@/%@", newDir, [imgs objectAtIndex:i]];

        if (![data writeToFile:savePath atomically:YES]) {
            NSLog(@"Saving of \"%@\" failed!", [imgs objectAtIndex:i]);
        }

        NSString *progress = [[NSString alloc] initWithFormat:@"%d / %u downloaded...", i, [imgs count]];
        NSLog(@"%@", progress);
    });
}

I also wonder how I can multi-task these GCD queues. For my test I just copy-pasted this code 6 times, where imageQueue# increments and [imgs count] is a fixed offset, solely for testing purposes.

Update

The cap runs in jaw-like patterns to about caps of 38~MB:

enter image description here

È stato utile?

Soluzione

Try using @autoreleasepool to give the autoreleased memory a chance to drain:

for (int i = 0; i < [imgs count]; i++) {
    dispatch_async(imageQueue1, ^{
        @autoreleasepool {
            NSString *path = [[NSString alloc] initWithFormat:@"%@/%@", damPath, [imgs objectAtIndex:i]];
            NSURL *url = [[NSURL alloc] initWithString:path];
            NSData *data = [[NSData alloc] initWithContentsOfURL:url];

            NSString *savePath = [[NSString alloc] initWithFormat:@"%@/%@", newDir, [imgs objectAtIndex:i]];

            if (![data writeToFile:savePath atomically:YES]) {
                NSLog(@"Saving of \"%@\" failed!", [imgs objectAtIndex:i]);
            }

            NSString *progress = [[NSString alloc] initWithFormat:@"%d / %u downloaded...", i, [imgs count]];
            NSLog(@"%@", progress);
        }
    });
}

Looking at the documentation, dispatch queues do provide autorelease pools, but there is no guarantee that they'll be drained, so for very memory intensive operations like this, you're probably well served by adding your own.

if your block creates more than a few Objective-C objects, you might want to enclose parts of your block’s code in an @autorelease block to handle the memory management for those objects. Although GCD dispatch queues have their own autorelease pools, they make no guarantees as to when those pools are drained. If your application is memory constrained, creating your own autorelease pool allows you to free up the memory for autoreleased objects at more regular intervals

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top