0

Some relevant info I am on OSX using GCD in Objective-C. I have a background task that produces a very large const char * this is then re-introduced into a new background task. This cycle repeats essentially until the const char* is empty. Currently I am creating and using NSStrings in the blocks and then going back to char* immediately. As you can imagine this does a ton of unnecessary copying of all that.

I am wondering how __block variables work for non-objects or how I can get away from NSStrings?

Or

How is memory managed for non-object types?

It is currently just blowing up with ~2 gigs of memory all from the strings.

Here is how it currently looks:

-(void)doSomething:(NSString*)input{
    __block NSString* blockCopy = input;
    void (^blockTask)(void);
    blockTask = ^{
         const char* input = [blockCopy UTF8String];
         //remainder will point to somewhere along input
         const char* remainder = NULL;

         myCoolCFunc(input,&remainder);

         if(remainder != NULL && remainder[0] != '\0'){
            //this is whats killing me the NSString creation of remainder
            [self doSomething:@(remainder)];
         }

    }

    /*...create background queue if needed */
    dispatch_async(backgroundQueue,blockTask);
}
Droppy
  • 9,691
  • 1
  • 20
  • 27
utahwithak
  • 6,235
  • 2
  • 40
  • 62
  • Can you add your code? For `__block`, see this question: http://stackoverflow.com/questions/7080927/what-does-the-block-keyword-mean – Code Different Oct 06 '15 at 21:33
  • You can just use the [`__block` modifier](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6). If you find it confusing, wrap the array in a simple Obj-C object and pass that around. – i_am_jorf Oct 06 '15 at 21:38
  • 1
    Update your question with relevant code. – rmaddy Oct 06 '15 at 22:27
  • `__block` is completely useless in your code, because `blockCopy` is never assigned to anywhere. You should just remove `__block` – newacct Oct 10 '15 at 07:26
  • @newacct And that will stop the memory starvation will it? – Droppy Oct 10 '15 at 10:28
  • @Droppy: No, because I never said anything like that. Please make comments that are relevant to the statement you are responding to. – newacct Oct 10 '15 at 17:48
  • You made a comment to a question where the OP states the his code is running out of memory. Your "just remove `__block`" doesn't solve that issue. – Droppy Oct 10 '15 at 18:41
  • @Droppy: That's why it's a comment. You don't seem to understand what comments are for. – newacct Oct 11 '15 at 07:28

1 Answers1

-1

There is no need to use NSString at all and no need to use the __block attribute:

-(void)doSomething:(const char *)input{
    void (^blockTask)(void);
    blockTask = ^{
         const char* remainder = NULL;

         myCoolCFunc(input,&remainder);

         if(remainder != NULL && remainder[0] != '\0'){
            [self doSomething:remainder];
         }
    }

    /*...create background queue if needed */
    dispatch_async(backgroundQueue,blockTask);
}

There is also little need to use recursion either, as an iterative approach is also possible.

blockTask = ^{
     const char* remainder = NULL;
     while (YES) {
         myCoolCFunc(input,&remainder);
         if(remainder == NULL || remainder[0] == '\0')
             break;
         input = remainder;
     }
}
Droppy
  • 9,691
  • 1
  • 20
  • 27
  • how will the memory be freed? – newacct Oct 10 '15 at 05:12
  • @newacct The method is passed a `const char *` and that does not imply ownership of that data and there was no information from the OP that it was allocated with `malloc()` and it was the responsibility of `doSomething:` to `free()` the data when it's done. My answer contains no memory allocation at all, and so the issue of freeing the memory is simply irrelevant, – Droppy Oct 10 '15 at 08:22
  • 1
    There's still an with memory management. If `-doSomething:` were synchronous, a caller could pass in a heap-allocated string and then free it when `-doSomething:` returns. However, since `-doSomething:` is asynchronous, the caller **must not** free it until the asynchronous work has completed, but the caller can't determine when that will be. So, unless the input is static or `-doSomething:` does receive ownership and must free the input, this interface is untenable. An interface with a completion handler would work. – Ken Thomases Oct 10 '15 at 12:39
  • But those details are not revealed by the OP. Why would I get involved in such details when they are obviously of no interest to him? The only reference to memory in the question is to it "blowing up" and that was solved in my answer by avoiding copying memory, and optionally, the use of iteration instead of recursion. – Droppy Oct 10 '15 at 12:58
  • Memory management is an essential consideration when doing asynchronous operations. Because it is asynchronous, it could take arbitrarily long before it executes; the caller has no idea. During this time, the memory must remain valid and unchanged (for the behavior to be preserved). So you must have a piece of memory that must remain valid indefinitely, and you cannot re-use it for other stuff indefinitely. That is a leak. There is no situation (whether allocated by `malloc` or not) where this would be correct. – newacct Oct 10 '15 at 17:48
  • @newacct And what if the string being passed-in is a global or a constant? The issue of memory management is not relevant to the answer as it was not mentioned in the question. – Droppy Oct 10 '15 at 18:37
  • @Droppy: It could be global (i.e. static storage duration). But again, whatever memory buffer you pass in, it would mean that it would have to exist for the rest of the program, and cannot be changed for the rest of the program. And there is only a fixed number of memory buffers of static storage duration in any program. So you've turned this function from one that can take any number of original strings indefinitely into something that can only process a fixed number of original strings in each program, which is the crappiest way something can be coded. – newacct Oct 11 '15 at 07:39