NSOperationQueue and Memory - ios

I've been using an NSOperationQueue and I have very strange memory issue with it.
I've tried reducing the issue to the simplest possible probleme and here I got:
in init:
_queue = [[NSOperationQueue alloc] init];
Later:
TestOperation op = [[TestOperation alloc] init];
[self.queue addOperation: op];
then in the method called by the main of the operation:
NSLog(#"I'm right here!");
If I call this thousands of times, my memory used just keep growing.
I've I only remove the NSLog from my method (thus calling an empty method) my memory don't change.
What am I doing wrong here??

When you add an operation to an NSOperationQueue, the operation queue owns the object and will be responsible of releasing it. Perhaps you are not giving enough time to the NSOperationQueue to release the memory and see the results?
For this cases you can surrounded it with an #autorelease block, but since the operation queue is the one responsible for the release of the objects I don't know if it will work. Is worth a try.

Related

why does memory leak still occur with ARC?Does it matter?

I used instruments to measure my app.It shows some memory leaks and my app is with ARC.
Here is a picture of the leak.
Question is:
1.We can see the size of memory leak is about 1KiB,most of it is smaller.Does it matter if I do not care about it?
2.We can see the address of the instance where memory leak happens,can I locate it (in the code,i suppose),so I can fix it,and how?
because there may be the use of strong instances of objects, that are not getting released. And always use weak references under blocks.
For Example
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
weakSelf.drawingView.center = weakSelf.center;
});
there can also be retain cycles.
Please use call trees for solution . then analyse code as well.

Memory Management in a Block Using Notifications

According to the Xcode instruments, my code has a memory leak (at #3). But I get the feeling I'm missing something in my mental model of what's going on, so I have a few questions about the following logic:
__block MyType *blockObject = object; //1
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.selectedObjects containsObject:blockObject]) { //2
[self.selectedObjects removeObject:blockObject];
[[NSNotificationCenter defaultCenter] postNotificationName:ObjectDeselectionNotification object:blockObject]; //3
} else {
[self.selectedObjects addObject:blockCart];
[[NSNotificationCenter defaultCenter] postNotificationName:ObjectSelectionNotification object:blockCart];
}
});
1) I'm using a __block reference because I'm executing this code async and don't want a reference to this variable copied to the heap. Is this a valid usage of __block even though I'm not mutating the variable?
2) Calling self.selectedObjects will create a retain on self. Does the block automatically release this after it has exited?
3) I apparently have a leak at this point, but I'm not exactly sure why. Is NotificationCenter retaining my __block object that is supposed to be disposed of after my block exits?
From the code you've shown, I don't see any problems...
1) Your object would not be "copied" onto the heap - it is already on the heap being an alloc'd object. Rather, it's reference count would be incremented by 1 as it is now owned by the block. You do not need the __block reference as you are not assigning anything to the pointer. In fact, you do not need blockObject at all and can just pass object.
2.) self should be released once the block is done. However, post a notification is synchronous (this block will not finish until all the objects responding to the notification are done).
3.) I'm not sure what the exact implementation that NSNotificationCenter uses, but it doesn't really matter because the posting is synchronous. It will call every observer of your notification and the selectors they want to receive your notification on
It seems as though you are running all this code within another block - can you paste the full method?
Please remove this answer if incorrect (you've already accepted) but I'm not sure you accepted because the answer worked for you.
I don't think you should be referencing self in that block - you will be creating a retain cycle.
__weak YourClass *weakSelf = self;
use weakSelf instead and cut the tie between the creator and the block floating on the dispatch queue?

Objective C: Autoreleased objects between threads?

If I have an autoreleased object and I need to provide it to a different thread, what is the best way to do so?
Let's say I have an object that is autoreleased in thread 0. I tell thread 1 about this object and it retains it because it needs it. Later then it's done, it releases it. No problem. When thread 0 runs again and empties its autorelease pool, it sees the retain count is 1 and because it's an autoreleased object it deallocs. Everything is fine, therefore threads don't matter. Right?
By the way this was originally an interview question. The interviewer insisted that an autoreleased object cannot be given to another thread. He seemed almost angry about it. More and more in tech interviews, I encounter ppl who believe they know everything.
You should not pass autoreleased object directly to other thread.
in this code
id _sharedVariable; // ivar
NSConditionLock *_lock;
- (void)thread1
{
id objectNeedToPass = [[NSObject new] autorelease];
[_lock lock];
_sharedVariable = objectNeedToPass;
[_lock unlockWithCondition:1];
}
- (void)thread2
{
while (true)
{
[_lock lockWithCondition:1];
id objectReceived = [_sharedVariable retain];
[_lock unlockWithCondition:0]
process(objectReceived );
[objectReceived release];
}
}
thread2 may see _sharedVariable hold a released object (and crash)
because it may do this
thread 1 create and autorelease object
thread 1 assign it to the shared variable
thread 1 release the object
object deallocated
thread 2 read the object
thread 2 retain the object - crash
to solve the problem, you should pass a retained object
id _sharedVariable; // ivar
NSConditionLock *_lock;
- (void)thread1
{
id objectNeedToPass = [[NSObject new] autorelease];
[_lock lock];
_sharedVariable = [objectNeedToPass retain];
[_lock unlockWithCondition:1];
}
- (void)thread2
{
while (true)
{
[_lock lockWithCondition:1];
id objectReceived = _sharedVariable;
[_lock unlockWithCondition:0]
process(objectReceived );
[objectReceived release];
}
}
however, this may cause memory leak if second thread failed to release the object and make code hard to maintain (retain/release are hard to balance)
There is nothing to worry about at all as long as you are following the normal Cocoa memory management rules. Every single way of "providing it to a different thread" will work fine as long as you are following the rules.
Pretty much any time you "provide something to a different thread", it is asynchronous (unless you are using locks to do synchronous cross-thread execution or something). Which means that the other thread may (and will likely) use it after the current function on this thread has gone out of scope. Any time you store an object that needs to outlive the current execution, it needs to be retained. If you are storing it in an instance variable or global variable directly, then you are responsible for retaining it, according to the memory management rules. If you are storing it in some kind of container object, then that object is responsible for retaining it. So pretty much if you follow the rules, there is nothing to worry about.
Let's consider a common way that people execute things on another thread, with -performSelector:onThread:withObject:waitUntilDone:. If waitUntilDone is false, this function stores the receiver, selector, and argument in some kind of object to wait until the other thread is ready to execute it. Therefore, this function must be responsible for retaining the receiver and object when it places it into this structure, and releasing it when the structure is destroyed. And indeed it does -- if you read the pre-ARC documentation for the method, it says "This method retains the receiver and the arg parameter until after the selector is performed."
So basically the memory management rules are sufficient -- if you store the object in an instance variable, you need to retain it. If you pass it to some other function, then it's their job to take care of it.
Don't. Pass an owning reference to the other thread. The other thread will take ownership of the object and release it when done with it.
With autoreleased objects, you can't tell when the sending threads autorelease pool will be drained, and can't be sure if it will be drained before the receiving thread gets it.

Is it absolutely leaks when "self" appeared in block?

- (void)netServiceDidResolveAddress:(NSNetService *)service {
dispatch_async(self.downloadQueue, ^{
NSData *data = [self downloadFromRemoteService:service];
dispatch_async(self.storeQueue, ^{
int img = [self.imageStore addImage:data];
dispatch_saync(self.renderQueue, ^{
[self renderThumbnail:img];
dispatch_async(dispatch_get_main_queue(), ^{
[[self thumbnailViewForId:img] setNeedsDisplay:YES];
});
});
});
});
}
this is the code from Apple WWDC2012 《Asynchronous Design Patterns with Blocks, GCD, and》,'self' as strong reference in blocks, Is this code all right? or how to avoid leaks in this situation?
No, self will not leak. self will however retained until after the last block has been executed. When the last block finished, the block gets deallocated which in turn releases self. At that time, and only IFF there are no other strong references to self, it will be deallocated.
Edit:
I could not resist to mention this (because the sample is from Apple himself -- take it with a grain if salt ;) )
So, at the very top there is the method downloadFromRemoteService. It's glaringly obvious that this is a network request. Network requests are inherently _asynchronous_.
One attribute of an asynchronous operation is that this operation cannot be made "synchronous" in a truly manner anymore. Once asynchronous - always asynchronous.
What's also obvious from the code sample, that the network request is oddly enough synchronous, Ohps!
What happens when wrapping a asynchronous task into a synchronous wrapper? Well, its at least "suboptimal": the calling thread will be blocked immediately until the result is available, then just return the result. That's a quite big amount of waste for resources (threads are limited and are costly to create and require a quite amount of RAM).
So, this code has a "code smell". It's a "bad programming practice". We should make this better. ;)
Objects automaticaly retained when mentioned in block. They got released when block deallocated. So this code is all right. Problems occur when your's self-object takes ownership of such blocks with self inside.
So you just need to release block when you don't need it any more.
There is a retain cycle in this code, as self retains self.downloadQueue (and the other queues), which retains all the blocks dispatched to it, including the block here, which in turn retains self when it is copied (which happens when it is dispatched to the queue).
However, it is a temporary retain cycle, because once the block is executed on the queue, the queue will (hopefully) release it, breaking the cycle.

Is This Safe? Possible Retain Cycle on Singleton as Self in Block

I'm pretty sure this is 100% safe, but I don't want to miss anything. I have the following code
- (void) scheduleControlSurfaceProcess {
[self.operationQueueForMessageProcessing addOperationWithBlock:^{
// do something
[self scheduleControlSurfaceProcess];
}];
}
where self is a Singleton. The block works splendidly as a non-main-thread thread. I do not see any memory problems in the profiler (which I don't trust much).
So, may I ignore the warning, "Block will be retained by an object strongly retained by the captured object?" If not, how can I insist that the block to get released (with ARC)? Getting the warning to go away is easy enough, but assigning id what = self seems like it would not solve the problem.
EDIT: as I realized quite late in this question, the real problem here was that I am rescheduling from within the block itself. This is obviously problematic, because each block retains the next.
NOTE: I am aware that there are lots of questions on this topic, but I'm not expert enough to know which, if any, situations are similar to this one.
- (void) scheduleControlSurfaceProcess {
__weak id SELF = self;
[self.operationQueueForMessageProcessing addOperationWithBlock:^{
id strongSelf = SELF; //Guarantee self doesn't go away in the meantime
// do something
[self.operationQueueForMessageProcessing addOperationWithBlock:^{
[strongSelf scheduleControlSurfaceProcess];
}];
}];
}
That would guarantee you won't have a cycle here. The warning is completely valid, self retains the operation queue, the queue retains the block, the block retains self. And round and round we go.
In my modified example the block will capture SELF and store it into 'strongSelf'. The strongSelf step isn't strictly necessary, but it will make sure the reference to self doesn't get niled during execution of the block.

Resources