> On 2 Jan 2015, at 1:46 pm, Roland King <r...@rols.org> wrote:
> 
> Having a handler block which refers to self is not in and of itself a 
> problem, very many blocks implicitly do. The block retains self, however in 
> most cases something else retains the block and the self reference goes away 
> when the block is released. The problem usually comes when the handler block 
> which refers to self is also a property of the object, eg myObj.completion = 
> ^{ .. block referring to myobj }. Xcode normally warns you if you even get 
> close to doing that however. 

Right. Well, my block refers to self, but it's not a property of self. Quickly 
trying it with a weak version of self shows no change of behaviour regarding 
memory usage, so I guess that was a red herring.

Just to be sure, I have:

<my 
object>...[owns]...NSURLSession...[owns]...NSURLSessionDataTask...[owns]...completion
 block...[refers to]...<my object>

I don't think this amounts to a retain cycle, because when the session has 
finished the task, it will release it, and its block, and those references to 
self (my object) that it has.


> 
> If that's happening then allocations should show you are amassing whatever 
> objects those are and never releasing them, does it? Or you can be old skool 
> about it and NSLog() dealloc() to see if it's getting called.


What appears to be amassing are 132KB malloc'd blocks (by the hundreds). These 
are created by HTTPNetStreamInfo::_readStreamClientCallBack(__CFReadStream*, 
unsigned long), down in CFNetwork. The stack trace is:

   0 libsystem_malloc.dylib malloc_zone_malloc
   1 libsystem_malloc.dylib malloc
   2 CFNetwork HTTPNetStreamInfo::_readStreamClientCallBack(__CFReadStream*, 
unsigned long)
   3 CFNetwork 
CFNetworkReadStream::_readStreamClientCallBackCallBack(__CFReadStream*, 
unsigned long, void*)
   4 CoreFoundation _signalEventSync
   5 CoreFoundation _cfstream_shared_signalEventSync
   6 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
   7 CoreFoundation __CFRunLoopDoSources0
   8 CoreFoundation __CFRunLoopRun
   9 CoreFoundation CFRunLoopRunSpecific
  10 CFNetwork +[NSURLConnection(Loader) _resourceLoadLoop:]
  11 Foundation __NSThread__main__
  12 libsystem_pthread.dylib _pthread_body
  13 libsystem_pthread.dylib _pthread_start
  14 libsystem_pthread.dylib thread_start


Which actually doesn't directly link it to anything in my code, though I think 
it's safe to say it's something set up by NSURLSession or NSURLSessionDataTask, 
which I do create in my code.

BUT, and this is a big but, I'm not sure if I'm interpreting Allocations 
correctly. I have it set to "created and persistent", and graphing these blocks 
shows a very close corrlation between them and the overall memory usage 
profile, so my interpretation is that these are predominantly responsible for 
the memory usage of my app. However, the shape of the graph does show that a 
lot of these blocks are freed, but not all, leading to the gradual increase in 
baseline allocation.

Here's the rough outline of the code I'm using to run the 
NSURLSessionDataTasks. This is a method of <my object>, and it is called once 
when there is data to begin downloading, and runs itself as long as there are 
items in the queue to be processed.

- (BOOL)                dequeueNextChunk
{
        // removes next URL from the chunks queue and starts it asynchronously 
downloading as a session. Returns YES if a chunk was dequeued, NO if not (queue 
empty).

        XVMediaChunk* chunk = [queuedChunkURLs firstObject];
        
        if( chunk )
        {
                // dequeue
                
                [queuedChunkURLs removeObjectAtIndex:0];
                
                // schedule download and start it

                [[self.session dataTaskWithURL:chunk.url 
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
                {
                        NSHTTPURLResponse* httpResponse = 
(NSHTTPURLResponse*)response;
                        
                        if( httpResponse.statusCode == 200 )
                        {
                                // got a valid response. If it's a valid chunk 
add the data to the chunk object and pass it along to the next step.
                                
                                if([httpResponse.MIMEType 
isEqualToString:@"video/mp2t"])
                                {
                                        chunk.data = data;
                                        
                                        [self processVideoChunk:chunk];
                                        
                                        // and schedule the next chunk in the 
queue
                                        
                                        [self 
performSelectorOnMainThread:@selector(dequeueNextChunk) withObject:nil 
waitUntilDone:NO];
                                }
                        }
                        else
                        {
                                // some other status was returned.
                                // code omitted that handes the error 
situation, which is not relevant to the leaks problem, as that occurs for valid 
responses only
                        }
                }] resume];
                
                return YES;
        }
        else
                return NO;
}


In this code, the object XVMediaChunk is just a simple container that 
associates a URL with a sequence number in the .m3u8 playlist. It also allows 
the downloaded data to be attached, as it is here, and further processed. In 
fact the remainder of the processing is very simple - the data is written to a 
NSFileHandle and the XVMediaChunk is discarded.

The overall function of <my object> is to download a .m3u8 playlist, extract 
the media content URLs from the playlist and queue the media chunks in order. 
Each chunk is then downloaded by the above method one at a time. If the 
download succeeds, the next item in the queue is downloaded. This process 
sustains itself until the queue becomes empty or there's an error. Other code 
resumes this dequeuing and downloading process by polling for the playlist at 
the rate determined by the .m3u8 target schedule time - that all works and is 
likely outside the scope of my problem.

--Graham




_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to