I see that many people are allocating and releasing NSStrings.
I understand that the benefit is that the string is being released immediately and not by autoRelease.
my questions :
does it effective and should i always prefer allocating and releasing on autoRelease?
what is more expansive - allocating and releasing immediately and then allocating again OR allocating, using and releasing in dealloc.
will appreciate any explanation.
Thanks
shani
In most cases it does not matter. I think you should use the autorelease since it makes the code more simple and the #"string" shortcut is very elegant.
The basic difference is the point in time when the release happens. Like I said, in most cases it does not make any difference. If you want to control the release time more closely, then you can also do that for autorelease by rolling your own NSAutoreleasePool pool.
I don't see how you could re-use a NSString. Reusing a NSMutableString instance might be slightly faster the recreating it but you won't see the difference. Focus on simplicity and maintainability of your code.
I think your question is wether to use [[NSString alloc] init] or [NSString string]. As long as performance is not an issue, always go with the simplest one. That would be the autoreleased version, because you don't need to release it yourself.
Related
I'm pretty new to Objective-C, as you may gather, and until recently, I hadn't really understood the need for all this AutoRelease malarky. I think that's mostly because I've started Objective-C with ARC, and haven't had any exposure to doing retains and release.
Anyway, my understanding now is that pre-ARC, if you created an object and needed to return a pointer to it as the returning object of the method/function, you would need to autorelease it, because you are unable to do the "[obj release]" after doing "return obj;"
Worrying about retains and releases isn't an issue with ARC. Does this mean that in our own code, there is really point in creating our own autoreleased objects? Ie, doing [[[Class alloc] init] autorelease]? From what I've gathered, we should still setup autorelease pools, but only because other frameworks or libraries may still return autoreleased objects, but we no longer need to explicitly create autoreleased objects ourselves - is this a fair understanding?
Thanks,
Nick
When using ARC, you do not want to do any memory management yourself. Specifically you will not be calling release and auto release because it does it all for you. In fact, the compiler should probably complain if you try to manage memory yourself.
Instead of [[[Class alloc] init] autorelease]; you'll just call [[Class alloc] init];
I recommend reading this blog post for some really good background on ARC and memory management in general.
Well, your understanding is quite correct. With ARC we do not release or autorelease any more. Just have to make sure that we assign nil (or some other reasonable value) to any reference to objects, which we do not need any more. In the worst case we could still constantly consume additional memory but the memory cannot leak any ore.
And yes, we still maintain autorelease pools for the sake of using framework libraries (linked ones) that may not use ARC.
To answer your question between the lines about the purpose of autorelease. This applies to non-ARC project only, of course.
In the good old days Objective-C did not offer any reference counting but its retain counting. Any allocated memory of objects, that are not retained (or have a retain count of 0) is considered free and may soon be claimed and used by other objects.
This means that every object needs to be retained after its allocation, assuming that you want to keep it around. When the object is not used any more then you need to release it. This comes with two risks. Well, alloc does retain it once automatically.
1) You may forget to release an object that is unused. In the worst case you may even loose all references to an object that stays in memory for ever since.
2) You may still refer to an object hat has been released already and then try accessing it which will most likely end in an BAD_EXC exception.
All this can be quite annoying. In order to get rid of some of these obligations for objects that don't stay around very long, the autorelease was invented. For temporary objects only you alloc it (release-count = 1) and autorelease it. That means that the object will be automatically released (retain count reduced by 1) within the next autorelease circle. But the object remains allocated for your method while it is being executed. Typically the reference variable would be a local one.
Sample:
-(void) myMethod{
AClass *someObject = [[[AClass alloc] init] autorelease];
// use the object
// probably hand it to another object if that takes ownership, i.e. add it ot an Array using addObject:
// don't care any more
}
And that not required any more when using ARC.
Let's say that I have a loop that returns a bunch of autoreleased NSData objects...
NSData* bigData = ...
while(some condition) {
NSData* smallData = [bigData subdataWithRange:...];
//process smallData
}
Under ARC, should I still wrap an #autoreleasepool around the while condition?
NSData* bigData = ...
#autoreleasepool {
while(some condition) {
NSData* smallData = [bigData subdataWithRange:...];
//process smallData
}
}
The reason why I'm asking is I see the living allocation count in instruments going through the roof for my NSData objects that invoke a dataWith... method as opposed to an initWith... method. When I use initWith..., the living allocation count is much, much less.
Is it better to prefer the initWith... methods whenever possible?
Yes you should still use autorelease pools when using convenience methods in a tight loop. All the old memory management rules still apply under ARC, the compiler is merely injecting RRs for you. Checkout the great post by the awesome Mike Ash!
Link
I think your issue is that the autorelease pool is supposed to go inside the loop. With the loop inside the autorelease block rather than vice-versa, the accumulated objects won't be released until after the loop finishes.
Under ARC, should I still wrap an #autoreleasepool around the while condition?
Yes. Autorelease Pools are still in place, and grow and pop as before. The compiler just adds and coalesces the necessary retains and releases operations when ARC is enabled (echoing Logan), based on the methods that are visible to the TU and default naming conventions.
Execution in ARC is nearly identical the manual reference counting: Autorelease pool stacks still exist. One difference is that the compiler may order the reference counting operations slightly different from the way you wrote it (not in an incorrect way), and may omit unnecessary retain cycles.
Is it better to prefer the initWith... methods whenever possible?
WRT minimizing heap growth compared to the autoreleased counterparts: Yes. That's always been the case. It's especially important on iOS devices, where memory is quite limited.
The exception to this is when the object may avoid an allocation. Example:
NSString * copy = [NSString stringWithString:arg];
in this case, copy may be [[arg retain] autorelease]. Note that in this case, copy is still autoreleased, but you should not usually go to great lengths to test the presence of such optimizations. Note: It's also better to use copy = [arg copy]...[arg release] here.
The other bonus is that your ref count imbalances are often caught earlier when the object is never autoreleased, and closer to the call site (rather than when the Autorelease Pool is finally popped).
Performance with large autorelease pools is actually much worse than most people would suppose. If you can avoid depending on them heavily (e.g. using alloc+init...+release), you can make your program noticeably faster. Explicitly creating autorelease pools is cheap, and can help minimize this problem. When allocations are large and/or numerous, avoid using autorelease on them where possible, and do wrap these sections in explicit autorelease pools.
When I perform a [NSString release] or [NSArray release] or [NSMutableArray release], what happens?
Does the memory became wiped out?
Or just pushed on the stack and dropped from the heap, or vise versa?
If I just want to dump memory when I am done with it, is "release" the best thing to use?
I am dealing with many matrices and don't want them sticking around using memory...
thanks
Just read the Memory Management Programming Guide and your questions will be answered.
Also, if you're dealing with a lot of matrices you may want to use manual autorelease pools.
When I perform a [NSString release] or [NSArray release] or
[NSMutableArray release], what happens?
The retainCount of the instance that you call release on is decremented. If it reaches 0 as a result of your call, then the instance will be deallocated.
Does the memory became wiped out? Or just pushed on the stack and dropped from the heap, or vise versa?
Not necessarily. The memory may become wiped out (in the sense that it no longer contains a valid object instance and may be overwritten by other things) once the retainCount reaches 0 (or less if you over-release something), but this is not guaranteed to happen immediately upon your call to release. The released instance may in fact stick around for quite awhile, if it is associated with an NSAutoreleasePool that is not drained frequently or if someone else has called retain on it.
If I just want to dump memory when I am done with it, is "release" the
best thing to use?
In general, yes. If you want really low-level control of things, you can also use malloc() and free() instead, which will release memory more immediately than calling release will.
When you perform a release, the use count in the object is decremented. If the use count decrements to zero (because it's not simultaneously "owned" by some other code or data structure), the heap space occupied by the object is marked as available for reuse.
When a new object is allocated, the heap is searched for an appropriately sized piece of reusable space, and if your recently freed piece is the first one found to match the required size, that storage is marked "in use" again and your old data is overwritten with the new object.
Note that this means that if you release an object too soon you may still be able to use it for awhile, but it can suddenly, at any time, go "poof" and turn into an entirely different object, causing mysterious errors.
I often see something like the following:
UIBarButtonItem *anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Show" style:UIBarButtonItemStylePlain target:self action:#selector(refreshPropertyList:)];
self.navigationItem.rightBarButtonItem = anotherButton;
[anotherButton release];
specifically where a local var, in this case 'anotherButton' is used and then later released. Is this exactly the same as autoreleasing it when it is alloc'ed and then making sure it is used before the method ends? i.e.:
UIBarButtonItem *anotherButton = [[[UIBarButtonItem alloc] initWithTitle:#"Show" style:UIBarButtonItemStylePlain target:self action:#selector(refreshPropertyList:)] autorelease];
self.navigationItem.rightBarButtonItem = anotherButton;
I ask because I see it done the first way a huge amount of the time, but it feels less error prone (for me) to just autorelease it outright. Is it just a matter of personal style or are there differences to these two approaches apart from one methodically releasing the object after all is done with it, and the other taking care to claim it to be released at the outset so one doesn't accidentally forget to, both having merits.
From Allocate Memory Wisely in Tuning for Performance and Responsiveness Table 7-2 Tips for allocating memory:
Tip
Reduce your use of autoreleased
objects.
Actions to take
Objects released using the autorelease
method stay in memory until you
explicitly drain the current
autorelease pool or until the next
time around your event loop. Whenever
possible, avoid using the autorelease
method when you can instead use the
release method to reclaim the memory
occupied by the object immediately. If
you must create moderate numbers of
autoreleased objects, create a local
autorelease pool and drain it
periodically to reclaim the memory for
those objects before the next event
loop.
When you autorelease something, you add it to a group of objects which will be released at some point in the future. This means that those objects still exist. Since iOS provides a limited amount of memory, it is suggested that you use release over autorelease whenever possible. You don't want your program to crash from low memory because you have a lot of autoreleased objects.
Excellent question. By autoreleasing, you are delaying the automatic release of objects. This is all fine and dandy and expected behavior when you need to return something from a method, but keeping that object in memory longer than is necessary can be impactful to your app.
By releasing it when you are done, you are freeing the resource at that moment and the memory could be used by another object at runtime. In Cocos2D it is standard practice to autorelease nearly everything and things seem to work OK, but it still rubs me the wrong way and I would not do that in general practice.
They accomplish the same thing. Some folks think you should avoid the use of autorelease whenever possible, so strongly prefer the release as soon as you can option. This was discussed here just yesterday.
In the code you cite, the difference between the two really is minimal. It's unlikely that anotherButton will be deallocated even after it's released because the assignment to self.navigationItem.rightBarButtonItem probably causes anotherButton to be retained.
The best argument for calling release as soon as possible, IMO and in this situation, is that by releasing anotherButton you're explicitly documenting the fact that you're done using it. Also, the static analyzer will ding you if you use anotherButton after the release. These two facts can help you avoid errors, and just make your code easier to understand.
The argument in favor of autorelease in a situation like this is that it might be marginally easier to read. I think there's a reason that Apple gives us all those convenience methods like +stringWithFormat: -- they let you create and use the string you want with one method rather than three.
I am having trouble understanding why NSLog reports "dog" when the code is run. I understand about retain counts and dealloc e.t.c. What simple thing am i missing ?
NSString *newFoo = #"dog";
[newFoo release];
NSLog(newFoo);
[#"String Literal" release];
is a noop;
NSString *literal = #"String Literal";
[literal release];
is also a noop. This is only the case for string literals; and you should never expect this behaviour anywhere else. (This is to say; even though you tell the object to release, it just doesn't.)
I believe it's because #"dog" is effectively treated as a constant by the compiler. It creates some subclass of NSString (which is a class cluster) which persists for the lifetime of the application.
Just discovered this question for the definitive answer, which is essentially the same as mine.
A String Literal is a special case.. http://thaesofereode.info/clocFAQ/
But in general assuming you are not using garbage collection just stick to the few simple rules..
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
more pertinently.. retain an object when you need it to stick around - balance it with a release when done. If you didn't create or retain it, you don't need to release it.
Sending -release to an object isn't like freeing the memory, it only signals that you are done with it. It may well still be around or it may not. You have no way of knowing, you don't need to know, and you shouldn't try to find out if it is used elsewhere, if clever apple code has decided to cache it, if it's a singleton, etc.
It may well still be valid but when you have sent release you have effectively said "I'm done" and not "reclaim this memory".
You are de-allocating the chunk of memory the pointer's pointing at, but the data is still there.
Releasing it doesn't automatically zeroes out that part of the memory.
So you can still read the data out just fine but it's just might be snapped (allocated) by something else down the line... but just not yet.
I'm not an ObjC coder by trade but as since its compatible with C that's I'm guessing from my C experience.
Although the object is probably released (not sure how Obj-C handles strings internally, some languages basically cache strings), you have not writted anything new in the memory of newFoo after you released it. The memory where the string was stored keeps its content, but could be overwritten at any time.
newFoo still points to the same adress in memory, but that memory could become anything else at any moment.
The way to really be sure that you don't point to potentially dirt memory is to set newFoo to nil after you released it.