I just ran into a problem.I use NSMutableArray to keep the Ad ids that need to be loaded. When one id is preloaded, I remove it from the array. Then I find out that, after remove, the unit id became a zombie.
I tried to reproduce this, and I find out that when the Ads id was pulled from array, it is not a zombie.It just become zombie after removed from array. But, there is still a NSString* refer to it, how can this happen? And If it will become zombie at this point, it should become zombie every time. But it only happens occasionally.
-(void)preloadNextRewardVideo
{
if([_allRewardVideoAds count])
{
NSString* adsName = [_allRewardVideoAds objectAtIndex:0]; //the element is not a zombie here
GADRewardBasedVideoAd* ads = [self ensureRewardVideo:adsName];
if(![ads isReady])
{
_currentRewardVideoName = adsName;
[_allRewardVideoAds removeObjectAtIndex:0];
GADRequest *request = [GADRequest request];
[ads loadRequest:request withAdUnitID:adsName]; //here, adsName is a zombie
_isRewarLoading = YES;
}
}
}
It's worth taking a close look at cocoa's memory management policies. The thing here (it seems to me) is that when your code assigns the string adsName, the object the preloadNextRewardVideo method is part of doesn't take ownership of the string-object that adsName is pointing at ('ownership' in this context means either allocating and initializing space for it through alloc/init, new, copy, etc, or sending it an explicit retain message). All you have is a local variable that points at a string-object owned by the _allRewardVideoAds array. Yes, making the assignment increases the retain count, but that retain is autoreleased, and limited to the scope of this method. As soon as this method ends, nothing is going to own that string-object, and it will deallocate.
This would not be an issue (and would not create the NSZombie flag) except that you just sent adsName to a different object (GADRewardBasedVideoAd* ads) that I'm guessing does not retain it either. Of course, ads is also autoreleased (nothing owns it outside of this method), but what is that, a race-condition over whether ads or adsName is deallocated first? I suspect you do have a race-condition because NSZombie only shows up sometimes, but I don't know enough about the internal mechanisms of autorelease to know how that might work.
I think NSZombie is just telling you that you have an object that is:
in use by an external object, and
due to be destroyed shortly though autorelease.
ARC is anticipating a problem, and using NSZombie to let you know.
You could fix this either by using the property setter (e.g. use self.currentRewardVideoName = adsName) which retains the string-object globally for this object, or by locally copying it (NSString* adsName = [[_allRewardVideoAds objectAtIndex:0] copy]) which makes sure that your object owns the string to the end of the method.
Since you don't enable ARC that means you need to manually manage the memory by yourself. Since you don't enable ARC that means you need to manually manage the memory by yourself. Even though most of APIs will return an auto released object from a method but that's not always be the case.
For this case, NSArray retains the objects contained in itself so it may not need to return an auto released object from objectAtIndex: method since it should be retained by itself as an optimization. In this case I suggest you to call retain the object when you get it from the array and release it before the end of this method. That would help for this case.
Related
I have this basic question where when we try to allocate memory to a string by using alloc init and add it to autorelease pool, and then try to release it, it doesn't crash.
NSString *value = [[[NSString alloc] initWithString:#"Hello"] autorelease];
[value release];
If I do the same thing for a array, it crashes.
I just want to know how string is different from array since both inherit from NSObject.
Do you mean it doesn't crash right away?
I.e. in the debugger after stepping over the release line?
The Autorelease-Pool will not have triggered at that point so the auto-release operation is still outstanding.
Either way - As always with memory errors they might not crash
instantly,
on your machine/operating system,
with this specific built,
with your current build settings,
...
or even at all.
It's a programming error nevertheless.
It is not guaranteed that the program crashes. Unfortunally there are several errors that does not cause a crash (immediately).
However there is an optimization for string literals. They live eternally regardless of the way they are created, retained or released. -initWithString: can be smart enough not to return a new instance of NSString.
First, undefined behavior is undefined -- it is not guaranteed to crash or do any other specific thing. Over-release is undefined behavior.
Second, what is happening here is that string literals evaluate to a pointer to a statically-allocated string object which lives for the lifetime of the program. It is not dynamically-allocated, and thus is not subject to memory management. retain, release, etc. have no effect on it. [[NSString alloc] initWithString:...] (as well as [... copy]) on an immutable string object simply retains and returns its argument directly, since there is no need to create a new object. So [[NSString alloc] initWithString:#"Hello"] is the same as #"Hello".
If I do this-
SomeObject* someObject = [[SomeObject alloc] init];
[[someObject release] release];
I presume my program wouldn't crash because the second over-release is acting on nothing.
Whereas
[[someObject autorelease] autorelease];
would crash because the object is released twice by being passed down the chain.
This is a matter of curiousity only, I guess I've never had a problem with it so far.
(See this answer for an explanation what oneway does.)
Your first example doesn't even compile, as void != nil. But if you simply call release two times on an object that has a retain count of 1, it'll for sure crash.
As for why release returns void while autorelease returns id: The first says I don't need this object any more, you may get rid of it. Thus, if it would return something and you would operate on it you're likely to operate on a dead object. By contrast, autorelease more or less says "Soon I won't be needing the object any more but let it stick around until I'm done with the current method."
So as you see they are similar in that they say I won't be needing this object any more, but they differ in the time: release says "you can get rid of the object now", while autorelease says "you may get rid of the object later".
I suppose this is mainly done for ease of use, as one could of course do without (and put every autorelease on its own line):
Whenever you release an object, you're done with it (or at least you should be). There is no need to return the object as it may well have been destroyed already and in any case the caller should not work with the object if it is not yet destroyed (i.e. someone else has a reference to it).
On the other hand autorelease is often used in conjunction with init/alloc and just marks the object for later destruction. Whenever using autorelease one can almost be sure that the object is being used afterwards. Whether you directly return it or work with it on your own (e.g. after [[[SomeClass alloc] init] autorelease]) it is very handy to have the object returned as it saves an explicit line of code for autorelease. It is also helpful to have the autorelease directly in the same line: On return [someObject autorelease] you can directly see, that this is an autoreleased object. If you use it with init/alloc you can directly see that this object does not need another release.
I believe, you've answered your question yourself. Call to autorelease can be in the very beginning of object's life, so probably you'll need to save some code lines by the following statement:
[anotherObject callMethodWithArg: [myObject autorelease]];
Indeed, that's helpful. However, you call a release, in the very end of the code, that uses your object. By saying immediate release, you are saying you don't need this object here anymore. So there's no sense in reusing it's instance. Another option is, that a release call can actually deallocate the object immediately, so returning an invalid pointer will not be a good idea =)
I am trying to know about release keyword. I allocated it once, and then I released it. then also the message was passed to that object. And it gives me output. But the retain count is zero. What is the reason behind this?
MyClass *obj=[[MyClass alloc]init];
[obj release];
[obj WhoAreYou];
I given "NSLOG(#"It is the problem.");"
I got the out put: It is the problem.
See this link..a simple tutorial on memory management..It says
You can think of release as saying
relinquish ownership of this object,
rather than destroy this object
That means when you release you are just losing your control over the object..You are not releasing it..Cocoa will release the variable if it is not referenced by anyone else
Can someone explain the difference between these two, the first one is taken from allowing xcode to automatically generate the declaration, the last one is taken from an example in "Cocoa Programming" by Aaron Hillegass.
- (NSString*)planetName {
return [[planetName retain] autorelease];
}
.
- (NSString*)planetName {
return planetName;
}
I am just curious whats going on, my understanding was that the method is returning a pointer to either nil or an existing string object. I don't understand the reason for retaining and then adding to the autorelease pool?
Consider:
NSString *planetName = [myPlanet planetName];
[myPlanet setPlanetName: #"Bob"];
[planetName length];
Without [[planetName retain] autorelease], the above will very likely crash.
retain/autorelease puts the object into the current thread's autorelease pool. That effectively guarantees that the object will remain valid until the pool is drained, which is typically after the current event -- user event, timer firing, etc... -- is done processing.
(1) Use #property and #synthesize. It generates correct getter/setters for you.
(2) Read the Cocoa Memory Management guide. It answers all of these questions quite well.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
In both cases, yes, they are both returning a pointer to either nil or the string object.
The difference is that the first code block handles memory management, the second does not. The second code block is assuming you are managing planetName somewhere else in your class instance, whereas in the first code block Apple is being as conservative as possible in keeping that memory from leaking. By putting the memory in the current autorelease pool it will be destroyed with the pool.
My recommendation would be to stick with the latter case and to be a little wiser about managing your own object instances than what XCode is auto-generating for you.
I understand you need to be careful with autorelease on iOS. I have a method that is returning an object it allocs which is needed by the caller, so in this situation -- as I understand it -- I need to send autorelease to the object in the callee before it returns.
This is fine, but once control returns to the phone (i.e. after my button click has been processed) it seems that the autorelease pool is released. I suspect this is how it is supposed to be, but I am wondering what is the best practice for this situation.
I have resorted to sending a retain message from the caller so that the object is not released and then explicitly releasing it in dealloc.
Is this the best approach?
The autorelease pool is typically released after each iteration of the run loop. Roughly, every Cocoa and Cocoa Touch application is structured like this:
Get the next message out of the queue
Create an autorelease pool
Dispatch the message (this is where your application does its work)
Drain the autorelease pool
What you describe is the expected behavior. If you want to keep an object around any longer than that, you'll need to explicitly retain it.
Using autorelease is a way of saying, "Object, I don't want you anymore, but I'm going to pass you to somebody else who might want you, so don't vanish just yet." So the object will stick around long enough for you to return it from a method or give it to another object. When some code wants to keep the object around, it must claim ownership by retaining it.
See the memory management guidelines for everything you need to know to use autorelease correctly.
Here is an examle provided in the Apple Memory Management document:
– (id)findMatchingObject:(id)anObject
{
id match = nil;
while (match == nil) {
NSAutoreleasePool *subPool = [[NSAutoreleasePool alloc] init];
/* Do a search that creates a lot of temporary objects. */
match = [self expensiveSearchForObject:anObject];
if (match != nil) {
[match retain]; /* Keep match around. */
}
[subPool release];
}
return [match autorelease]; /* Let match go and return it. */
}
Yes, that's the best approach. Autorelease is really only intended for interactions in code that you know. Once you're storing an object, you should either know that the object that holds a reference will not die/go out of scope until you're also done with the object, or you need to retain the object.
It is only guaranteed that autoreleased objects will be released after the end of your method. After all, the method that called your method could have created its own pool and release it right after your method.