I have a beginner's question about releasing variables and not wasting memory...
I don't quite understand when to release variables. I understand that I should always do this if I have assigned them in my header file (in my #interface section and my #property commands). I release them in my -(void)dealloc function.
However, what am I supposed to do with variables that I happen to use in some of my methods, e.g.:
for (int temp = 0; temp < 3; temp++) {
// do something...
}
[temp release];
This is obviously wrong (at least xCode tells me so), as 'temp' is undeclared. But why? I've declared it as an int and temp thus takes up space in my memory, I'm sure. How do I tell the program to free up the space temp has taken after I don't need it anymore? I'm sure this is obvious, but I simply don't get it.
I'd be very happy for any suggestions for a beginner of how not to be a memory pig and to have 'memory leaking' everywhere in my apps...
You declared it as an int in the scope of the loop. Once the loop is done, it goes out of scope.
Also, you can not release an int, which is a primitive type. You can only release a subclass of NSObject. A good rule of thumb is that you eventually have to release anything that you called alloc or retain on.
Edit: For your edification, memory management only applies to objects allocated from the heap. That would be NSObjects obtained via "alloc" or must C-level memory allocated with something like "malloc()". Declaring a variable like "int x" is called an "auto" variable in that is is created on the stack and will AUTOmatically disappear then that block ends (the end of a "block" being the end of the function or perhaps the end of a {} pair or even the end of a for/if/while block.
Since Objective-C is basically just a special version of C (with messages), it does not create permanent objects unless you explicitly tell it to. This is different form languages like Python or Javascript.
You only need to release objects, and temp is an int, not an object.
As far as when to release objects, Apple's docs explain that better than I can: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
You do only release objects, and not primitive types. For example you create an array with
NSArray *myArray = [[NSArray alloc] init];
This initialization allocated memory which you have to free after your done using your array, it's your responsibility, else there will be memory leaks. You can do that in the dealloc section of a controller, or at the end of a method, or even after you've enumerated through the array and no longer need it.
If you create instances of objects with other methods than alloc, copy or new(rarely used) you have to release them. If you call retain yourself on an object you have to release it as well.
Please refer to apples memory management rules, which have been posted earlier.
There are two ways to store information in RAM in C and c like things, primitives which are allocated automatically by the compiler, and memory chunks allocated by you in your program.
Variables allocated for you by the compiler are called "automatics" and can be marked by the essentially unused (because it is the default) "auto" keyword. Automatics are bound to the scope in which they are declared and go away when it ends. Regular variables, like "int x" are automatic.
Notably, pointers are typically automatic. However, the things they point to are not. Those would be the thing you asked to be allocated.
In objective-c, things are allocated with the alloc message. However, sometimes a class will call this for you, so you might not see it. To help make it clear what you should do, there is a tradition: If you get an object where you alloc'ed it, got it from a class method with the word "copy" in the method name, or sent it a "retain" message, then you own a share of it, and it won't go away until you send it a release message.
If you didn't get the object through one of those means, you must not release it, because you don't have a share in it.
So, in summary: regular variables (int, short, char, double, float, long) are automatic, no need to allocate it. Pointers are also automatic, however, the things they are pointing to are not. In obj-c, you own a share if you alloc'ed it, copy'ed it, or sent it a retain message.
You can't release an integer...
Release works only with instance of Objective-C classes.
Variables such as integers are placed on the stack, and they does not persist after a function/method call, unless allocated explicitely.
You only release objects. If you use the alloc, init procedure to create an object you must release it. If you retain an object you must release it. If you use a method that has the word "create" in it, you must release it. Anything else, the system will handle for you.
Primitives do not need to be released, only objects.
Biggest thing to keep in mind is that whenever you "alloc" or "retain" an object, put a corresponding "release" or "autorelease".
you see an error on the line [temp release]; because temp is not in scope. temp will not be seen outside of the for loop you created.
you do not need to clean up the memory of temp, since you have not claimed ownership of it(see Memory Management Rules): http://developer.apple.com/library/ios/#documentation/general/conceptual/DevPedia-CocoaCore/MemoryManagement.html
examples of objects where you do not need to release/manage memory:
NSArray *myArray = [NSArray array];
NSNumber *myNumber = [NSNumber numberWithInt:5];
NSString *myString = #"Hello World";
NSInteger i = 5;
int x = 2;
examples of objects where you do need to release/manage memory:
NSArray *myArray = [[NSArray alloc] initWithObjects:#"Hello", #"World", nil];
NSNumber *myNumber = [[NSNumber alloc] initWithInt:5];
NSString *myString = [[NSString alloc] initWithString:#"Hello World"];
-
typically, when your completely done using an object you own, you clean up its memory
see apple's docs for explanations on properties: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW1
setting a property with assign or readonly: you should not worry about releasing its memory, as you don't own it
property with retain or copy: you claim ownership of the object and need to release it at some point
this answer won't answer/solve all memory management questions/concerns, but it may shove you in the right direction
Related
Which one of these is better practice?
A) retain and release the object myself later
NSMutableArray* array = [[self getArray] retain];
....
[array release];
B) autorelease from the function returning the object
getArray {
NSMutableArray* returnedArray = [[[NSMutableArray alloc] init] autorelease];
.....
return returnedArray;
}
The simplest rule of thumb when it comes to memory management in Objective-C is that you should release anything that you've explicitly allocated (alloc), copied (copy), newed up (new), or retained (retain).
The release should be done within the scope of the aforementioned actions. If you allocate space for an object that is returned by a method, you should autorelease it before returning it. So, given the two options you've provided, B is the recommended practice.
You could read and follow Apples guidelines on memory management and performance.
Personally I think the reasons for choosing one way over the other:
Using Autorelease pros:
You can't stuff it up, memory will be freed at some point. That I like to think of as "falling into the pit of success".
cons:
Using autorelease a lot may cause you memory problems as lots of objects build up awaiting be released by the autorelease pools.
Using retain/release pros:
More control when your memory is used/freed.
On ios apple recommends that you use release instead of autorelease whenever possible to keep the size of the pool small.
cons:
Like C/C++ malloc/free new/delete you have to be careful to keep them matched up and it is easy to stuff that up, causing memory leaks.
For member variables you have no choice, retain/release is it.
I think, whichever style you choose comes down to the situation your code is in and choosing the best style based on there pro's and con's. I don't think there is any one answer to this.
If you want to return an object you have to use the second approach. In all cases where possible you should use the retain-release approach because this uses less memory.
If you new, alloc init, retain, or copy (NARC) an object, you have to release it.
When the name of a method starts with any of those words, it means it's being created for the caller, who has the responsibility to release the object when he is done with it.
Otherwise the method returned is not owned by the caller, and he has to indicate he wants to keep it calling retain on the object.
If you can choose, don't abuse autorelease when memory is a concern.
Some comments:
The first rule logically results in the second. Example: if the outcome of a function (the returned object) survives the execution of the function, all the function can do is autorelease the object.
Unless there is a memory/performance concern, the overhead of automatic memory management is better than the memory leak chances plus the increased developing time.
Try to retain/release symmetrically. Example: if you retained on init, then release on dealloc. Same for viewDidLoad/viewDidUnload.
If you use #property(retain) you have to release in dealloc.
Example:
// created with autoreleased, just call retain if you intend to keep it
NSString *orange = [NSString stringWithString:#"orange"];
// created for the caller, you'll have to release it when you are done
NSObject *apple = [NSString initWithString:#"apple"];
It's about the instance method of NSMutableArray "initWithCapacity".
From documentation, the Return Value is described as:
Return Value
An array initialized with enough memory to hold numItems objects.
The returned object might be different than the original receiver.
There seems to be a typo at "different than", my guess is it should be "different from". And also if the returned object is indeed different from the original, do we have to worry about releasing the memory associated with the original object ?
Hope that somebody knowledgable on this can help ...
http://developer.apple.com/library/mac/#documentation/cocoa/reference/foundation/Classes/NSMutableArray_Class/Reference/Reference.html#//apple_ref/occ/cl/NSMutableArray
You have created an object with alloc, and you are responsible for the memory of that object. The fact that initWithCapacity: may return a different chunk of memory than what originally came from the call to alloc does not change that.
Initializer methods in Cocoa are allowed to deallocate the instance they are passed and create a new one to be returned. In this case, it's necessary for initWithCapacity: to do so, since you're actually asking it to reserve more memory that alloc didn't know about and couldn't have allocated.
This is the reason that alloc and init... should always be paired: [[NSMutableArray alloc] initWithCapacity:10]
Regarding initWithCapacity: specifically, bbum (who knows of what he speaks -- Apple engineer) says that it's usually unecessary. It does not preclude you from expanding the array past the specified size. All it does is potentially allow the array to do some initial optimization*; unless you've measured and it makes a significant difference, it's probably not necessary.
*See Objective-c NSArray init versus initWithCapacity:0
Any time you use a method that contains the word alloc then you are responsible for releasing the memory. For example if you did the following
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity:10];
//Store data into the array here
//Once done you need to release the array
[myArray release];
--Editied post because I meant to type alloc and used init instead.
I have managed to get myself confused about some elements of memory management. I am new to objective-c, and memory managed languages generally.
I have read the memory management guidelines, but I remain confused about a couple of things.
1) Is there any need to clean up ivars, and method variables that are not retained by any object. For instance
-(void) someMethod{
int count = 100;
for (int i=0; i <count; i++) {
NSLog(#"Count = %d", i);
}
}
What happens to the "count" var after the method is complete?
If a method allocates lots of temporary variables, do those get removed from memory as long as they are not unreleased, alloc'd objects? Or do i need to set them to nil in some way?
2) If i have a static variable, for instance an NSString, do I have to do anything for that to be removed from memory when the class is dealloced?
3) I have noticed that NSStrings seem to have a retainCount of 2147483647 which wikipedia tells me is the max value for a 32 bit signed integer.
http://en.wikipedia.org/wiki/2147483647
myString retainCount = 2147483647
-(void) someMethod{
NSString *myString = #"testString";
NSLog(#"myString retainCount = %d", [myString retainCount]);
// logs: myString retainCount = 2147483647
}
What happens to this at the end of the method? Does this memory ever get emptied? The string is not being referenced by anything. My understanding is that the #"" convenience method for NSString returns an autoreleased object, but whats the point of autoreleasing something with a retainCount of 2147483647 anyway? In that case, whats the point of retaining or releasing ANY NSString?
I am well aware that retainCount should be ignored, but it just bugs me not to know what's going on here.
4) Does this matter at all? I know that the memory associated with an NSString isn't much to write home about, but I want to be a good memory management citizen, and I'm more interested in best practices than anything else.
Retain/release only matters for objects, not int, bool, float, double or other built-ins. So use it for id or other classes that you hold a pointer to an object. In your example, count doesn't need to be retained or released. It is allocated on the stack which is automatically cleaned up when the function returns.
You do need to deal with any local objects you alloc. Those are created with a retainCount set to 1, so you need to either hold on to them for later or release them. Most Cocoa functions (that don't start with copy or alloc) return an object that is autoreleased. This means that they will have release called on them later -- you can only hold these after the function if you call retain on them. If you want them to be cleaned up, you don't need to do anything (calling release would result in too many release calls).
If you have a static variable pointing to an object, then it is not touched when objects of that class are dealloced. If you want it to be released, you have to call release on it. If the static is an int, bool, or other built-in, you don't (can't) call release on it. That's part of the global memory of your app.
NSStrings that are set to string literals should not have release called on them. The retainCount is meaningless for them. That value is also -1 for signed int values.
If you do this -- [[NSString alloc] initCallHere:etc] -- you have to call release on it. Most of the time you get strings, you don't use alloc, so you don't need to call release. If you retain one, you need to call release.
Yes, it does matter. Over time leaks will cause the iPhone to kill your app.
You don't need to worry about count cause it's an integer, a primitive data type, not an object.
I've read that those just go away upon app termination or if you explicitly release them.
You are right in that you should not worry about the retain count in that way. Cocoa automatically gives #"" (NSConstantString objects) the absolute highest retain value so that they cannot be de-allocated.
You are over complicating the subject. The point of the three guidelines is so that you know that you only have to worry about memory management in three specific situations. Apple gives you these guidelines so that one doesn't have to worry about the specific internals for every single class (like manually tracking retainCount), not to mention that sometimes Cocoa does things differently (as with NSConstantString). As long as you remember these guidelines, you really don't have to know the very gritty details of what's going on underneath (of course, an understanding of the retain count concept helps, but compare this to manually tracking it).
I don't know which guide you read specifically, but if you haven't given this one a try, I highly recommend it. It summarizes the three guidelines in a concise and direct manner.
The Cocoa memory management rules only cover Objective C objects.
Local variables (non-static) are cleaned up when any subroutine or method exits (actually the stack memory is just reused/overwritten by subsequent subroutines or methods in the same thread). Constants which require memory (strings) and static variables are cleaned up when the app is torn down by the OS after it exits. Manually malloc'd memory is cleaned up when you manually free it.
But any object you alloc or retain: (whether assigned to an ivar, local, global, static, etc.) has to managed like any other object. Be careful assigning objects to global variables, unless you are really good at retain count management.
In the code below, will tapsLable.text be deallocated when tapsMessage is released or does the assignment operator somehow increment the retain count so that tapsLabel.text continues to be available?
NSString *tapsMessage = [[NSString alloc] initWithFormat:#"%d taps detected", numTaps];
tapsLabel.text = tapsMessage; // tapsLabel is a UILabel object
[tapsMessage release];
Here's a tip
You can write the retainCounter for the object then you see what it is before and after the assignment.
e.g. NSLog( #"%d", [tapsMessage retainCount] );
That way you can answer such questions in the future by just writing out the retainCount as it always depends on how the property is declared.
tabsLabel.text is a property on tapsLabel. I think it's a string property that does [target copy] on assignment. Nevermind the details, yes, the assignment operator either increments the retain count or copies the value, so you can release tapsMessage and it is still available in tapsLabel.text.
Read more about properties here.
EDIT: looked up UILabel in the header, yes, it does a copy for the text property.
#property(nonatomic,copy) NSString *text; // default is nil
EDIT: to expand on the important question in the comment
How does anyone know when to release and when not to if you have to look at the implementation details of every object you assign something to?
You just follow the memory management rules. The point of the refcounted environment is exactly that there is some "loose coupling" going on between the objects in terms of memory management. As long as you retain and release properly, it is not your concern whether someone else also retains and releases these same objects, as long as all involved parties have their retains/releases matched.
In the first line, you have allocated and initialised an NSString. You own this object according to the memory management rules, which means you are responsible for releasing it.
In the second line, you are assigning the tapsMessage string the text property. This property (assuming tapsLabel is a UILabel) is declared with the copy attribute. For immutable strings (NSStrings), asking for a copy simply increments the retain count, since there is no need to make an actual duplicate of the data (the data can never change). Since UILabel has made a copy of the string, it has claimed ownership as well (objects can have more than one owner).
In the third line, you relinquish your ownership but the string still has one owner (the label), so the object is not deallocated.
It will not be deallocated.
I have some code which I think has extra release statements.
Is the code incorrect?
What is the end result?
I don't understand memory management well yet - even after reading lots of articles and stackoverflow answers. Thanks for straightening me out.
Update: The attached snippet works fine, but other code has the over-release problem
NSMutableArray *points = [NSMutableArray new];
for (Segment *s in currentWorkout.segments) {
[points addObjectsFromArray:[s.track locationPoints]];
}
[routeMap update:points];
[points release];
Your code is correct, but inadvisable. new acts as an implied alloc, which creates the object with a retain count of 1.
I think the last time I used new was in 1992; it's not wrong, but alloc/init is considered better practice, because it is clearer what you are doing. Please read Apple's guide to memory management, it is a comprehensive summary of the situation.
No messages can safely be sent to a deallocated object. Once an object has been released a sufficient number of times, it's deallocated. Any further messages sent to that object are going to an object that isn't there anymore. The precise result isn't completely predictable, but it usually ends in a crash. If you're less lucky, it could end in much stranger ways — for example, you could theoretically wind up with an Object A getting dealloced early and Object B allocated in the same memory location, then Object B receiving messages meant for Object A that Object B does understand but isn't supposed to receive at that time.
Basically, follow the rules. Think of it in terms of ownership. If you've claimed ownership, you need to release that ownership. If you don't own the object, you must not release it.
Take a look at this article online: http://weblog.bignerdranch.com/?p=2 .
It seems to imply that calls to release without a corresponding preior call to retain will result in a BAD_ACCESS error.
A short answer is, if you increasing the retain count of an object and you no longer are using it you should release it, otherwise you shouldnt...
So when ever you do a [objectName alloc] you are increasing the count by 1, when you use such methods as [NSString stringWithString:] these methods return an autoreleased object so you dont need to release it...if you instead did something like [[NSString stringWithString:]retain] then you are increasing the strings retain count and you should release it after you are done using it.
Im not too sure if new increases the reference count (i suspect that it would), you can always check your retain count by doing [object retainCount]... though note that even if the retain count is greater than 0, it does not mean you need to release the object, because some other class might have a reference to the object and therefore has its retain count increased by one and its the responsibility of the other class holding the reference to release it.
Hope this helps
you should use:
NSMutableArray *points = [[NSMutableArray alloc] init];
[...]
[routeMap update:points]; //if routemap stores the points, it will need it's own release retain
[points release]; //if there is a retain in the method above, reference will not be cleared
if unsure, use the build->analyze command, it will search your code for leaked references
you can get the official memory management guide from https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html