3

I'm developing an iOS application which is using socket connection to share it's screen with another device. It's working well and it's sending the screenshots but the memory which the application is allocation keeps on growing and growing until it receives memory warning after several seconds and then it starts sending wrong data to the receiving server so that the server crashes. Here is the code I use right now:

  • The method in my main ViewController.m:

    -(void) activateShareScreen {
    newClient *nc = [[newClient alloc] init];
    [nc connectToServerUsingCFStream];
    dispatch_queue_t backgroundQueue = dispatch_queue_create("No", 0);
    dispatch_async(backgroundQueue, ^{
        while (true){
            @autoreleasepool {
            UIGraphicsBeginImageContext(mapView_.frame.size);
            [mapView_.layer renderInContext:UIGraphicsGetCurrentContext()];
            bitmap = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            }
            [nc writeToServer:UIImageJPEGRepresentation(bitmap, 50)];
        }
    });
    NSLog(@"Share screen button tapped");
    

    }

  • And it is calling this file:

    #import "newClient.h"
    
    

    @implementation newClient {

    NSInputStream *iStream;
    NSOutputStream *oStream;
    
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    
    BOOL boolean;
    

    }

    -(void) connectToServerUsingCFStream{

    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
                                       (CFStringRef) @"192.168.1.9",
                                       8080,
                                       &readStream,
                                       &writeStream);
    
    if (readStream && writeStream) {
        //CFReadStreamSetProperty(readStream,
        //                        kCFStreamPropertyShouldCloseNativeSocket,
        //                        kCFBooleanTrue);
        //CFWriteStreamSetProperty(writeStream,
        //                        kCFStreamPropertyShouldCloseNativeSocket,
        //                        kCFBooleanTrue);
        iStream = (__bridge_transfer NSInputStream *)readStream;
        oStream = (__bridge_transfer NSOutputStream *)writeStream;
      //  [iStream setDelegate:self];
        //[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
        //                   forMode:NSDefaultRunLoopMode];
        [iStream open];
    
       // [oStream setDelegate:self];
        //[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
        //                   forMode:NSDefaultRunLoopMode];
        [oStream open];
       // data = UIImageJPEGRepresentation(bitmap, 50);
        boolean = YES;
    
    • (void) writeToServer:(NSData *) data{ int len; uint32_t length = (uint32_t)htonl([data length]); //[oStream write:(const uint8_t *) "/n" maxLength:2]; // Sending out the length of the screenshot image and then the image len=[oStream write:(const uint8_t *)&length maxLength:4]; NSLog(@"len=%d",len); //[oStream write:(const uint8_t *) "/n" maxLength:2]; len=[oStream write:(const uint8_t *)[data bytes] maxLength:[data length]]; NSLog(@"len=%d",len); //[oStream write:(const uint8_t *)"/n" maxLength:0]; }

    /*- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode { switch(eventCode) { case NSStreamEventHasSpaceAvailable: if(stream == oStream) { dispatch_async(dispatch_get_main_queue(), ^{ @autoreleasepool {

    int len; uint32_t length = (uint32_t)htonl([data length]); // Sending out the length of the screenshot image and then the image len=[oStream write:(const uint8_t *)&length maxLength:4]; NSLog(@"len=%d",len); if (len<0) { [oStream write:(const uint8_t *)[data bytes] maxLength:length]; } [oStream write:(const uint8_t *)"/n" maxLength:0]; } }); } }

Am I the only one who has experienced that kind of problem? Am I using wrong methods? Any suggestions how to solve the problem?

Here's a screenshot of Instruments when I run the app in it: Screenshot from instruments tool

WWJD
  • 1,104
  • 4
  • 12
  • 31
  • your activateScreenshare runs a tight loop and the autoreleasepool is misplaced, that already might cause the problem. But to ultimately pinpoint the problem use Instruments. – Volker Mar 26 '14 at 10:34
  • Have you tried running the app in instruments to see where memory is alloced and if you have a memory leak? – Robert J. Clegg Mar 26 '14 at 11:08
  • I put the autorelease pool inside the loop and it's the same result. – WWJD Mar 26 '14 at 12:32
  • Why is the increase in memory so sudden at the end? What is that code doing? – Robotic Cat Mar 26 '14 at 13:21
  • That's when I start running the activateShareScreen button. – WWJD Mar 26 '14 at 16:06
  • see http://stackoverflow.com/questions/5121120/uigraphicsgetimagefromcurrentimagecontext-memory-leak-pdf-previews – Volker Mar 26 '14 at 16:56
  • 1
    I know you've moved on in the last four years (lol), but needless to say, your `writeToServer` call needs to be in the autorelease pool, too. And if you see unbounded growth like this, you need to use either the Xcode "debug memory graph" feature (which shows you what's leaking and where the lingering strong references are) or the old faithful Allocations instrument when you profile the app to identify what is leaking and where it was retained. And the static analyzer (shift-command-B or "Analyze" on Xcode's "Product") is remarkably good at finding issues in Objective-C code. – Rob Jan 14 '18 at 22:45

1 Answers1

2
@autoreleasepool {
    while (true){
       ...
    }
}

The autorelease is never done, it should be placed INSIDE the while loop

Jerome Diaz
  • 1,746
  • 8
  • 15