dispatch_async, memory doesn't be freed after execution

459 views Asked by At

I have a function which uses dispatch_async:

- (IBAction)action:(id)sender {
    int i=10000;
    NSString * data;
    dispatch_queue_t queue = dispatch_queue_create("com.wang.queue", NULL);
    __weak ViewController*  weakSelf = self;
    while(i>0)
    {
        @autoreleasepool {
            data = [[NSString alloc]initWithFormat:@"%i",i];
            NSString * str = data;
            dispatch_async(queue, ^{{
                [weakSelf print:str];
            }});
            i--;
        }
    }
}


-(void) print:(NSString*)str
{
    NSLog(@"%@",str);
    str = nil;
}

And then I press the button for five times continuously. After it was run complately,the memory didn't reduce. So I use Instrument to analyza where the memory was occupied. like this:

img.bbs.csdn.net/upload/201411/19/1416403576_473540.png

It showed that the memory of "data" was freed. It is "VM:performance tool data" who occupied the memory. The detail is :

img.bbs.csdn.net/upload/201411/19/1416403630_487530.png

I think something about "dispatch_async" was never freed.

Who can tell me what make the memory performed like this? Appreciate !

1

There are 1 answers

1
Rob On

A couple of thoughts:

  1. You are using NSString objects, but there are all sorts of caching/optimizations of NSString that can skew this sort of analysis. You should generally be wary of doing memory analysis with NSString objects. You might want to repeat this with NSObject or some custom class. I don't think it's the problem here, but something to always be cognizant of when debugging memory allocations.

  2. You're using @autoreleasepool but you have no autorelease objects. I presume you put that pool in just to be cautious, but your main data/str object is not autoreleased, so this pool probably doesn't buy you anything. Also, FYI, GCD employs its own autorelease pools, anyway.

  3. Even if you did have autorelease object, the data variable is defined outside of the scope of your @autoreleasepool and you're never eliminating that final strong reference inside the pool, so the pool would not accomplish anything. You should use the narrowest possible scope possible for your variables. In this case, I'd simply retire the data variable and just use your local str variable.

  4. It was suggested that you might have a retain cycle (a.k.a. a strong reference cycle). There is no such cycle, at least not in the code shared with us thus far.

  5. Having said all of that, the "performance tool data" seems, to me, to be unrelated to the 10,000 objects you are creating. You have 347 objects accounting for 180 mb.

    I wonder if this "performance data" is something that Instruments, itself, is creating (e.g. snapshotting, stack traces, etc.). I've done some experimentation and have been unable to reproduce the behavior you describe. I have tried changing the Xcode scheme to turn on a bunch of logging options (e.g. zombies, memory checks, logging, etc.) and I have tried changing Instruments to record the maximum amount of information (e.g. frequent snapshots, etc., keeping discarded items, recording reference counts, etc.). All of this was to no avail.

    Perhaps you can share what Instruments settings you might have turned on (or try turning off a few). Likewise with the scheme for your app (making sure you've turned off unnecessary logging). Also, please edit your question, providing us details regarding what version of Xcode/Instruments you are using, as well as the target OS version, etc.