I've searched far and wide for its meaning. My guess is that I somehow have a corrupt stack. I get
tiny _ free_ list_ add_ ptr
on the 16th call of the line that says:
NSDateFormatter *theFormatter = [[NSDateFormatter alloc] init];
What is the cause of the problem? Am I correct in thinking that I have a corrupt stack?
- (NSString *)formatDate:(NSString *)uglyDate withFormat:(NSString *)theFormat {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDateFormatter *theFormatter = [[NSDateFormatter alloc] init];
[theFormatter setDateFormat:theFormat];
NSDate *realDateUgly = [NSDate dateWithNaturalLanguageString:uglyDate];
if (realDateUgly == nil)
realDateUgly = [NSDate dateWithString:uglyDate];
NSString *prettyDate = [[NSString alloc] initWithString:[theFormatter stringFromDate:realDateUgly]];
[pool drain];
[pool release];
[theFormatter release];
return prettyDate;
}
I doubt you need a pool here.
You're over-releasing the pool. drain is the same as release in non-GC code. (release is just as redundant in GC code, because then it's a no-op.)
You're leaking prettyDate. You're supposed to autorelease it. (Of course, that won't work with the pool around it, which is a good reason to kill off that pool.)
Once you review the Memory Management Programming Guide for Cocoa and fix your memory-management problems, you should either find the problem fixed or at least be better able to track it down.
If you do still have the problem after you fix your memory management, please edit your question to include the complete stack trace.
I assume you're crashing in tiny_free_list_add_ptr. If so, tiny_free_list_add_ptr sounds like a function that a malloc implementation would use to keep track of memory blocks on the heap. If the heap is corrupted, I would expect a function like this to crash.
You're probably over releasing something (like the auto release pool that peter pointed out) here or in another method.
You should try running with the NSZombiesEnabled environment variable set. See http://developer.apple.com/technotes/tn2004/tn2124.html#SECFOUNDATION
I'd be willing to bet the problem is this:
[pool drain];
[pool release];
In a non-GC app, drain 'behaves' like release. 'Behaves' is the word used in the documentation, but the documentation is a bit ambiguous when you need to be pedantically precise as to exactly what happens when -drain is called. To me, at least, 'behaves' allows for a little bit of wiggle room, especially when compared to 'drain is exactly the same as release', which leaves a lot less room for interpretation.
The reason I bring this up is 'what happens to the autorelease pool after -drain is called?' I could not find a satisfactory answer in the documentation to this question. In different places, the documentation implies that when running in GC mode, -drain behaves as a 'hint to the GC system' and calls objc_collect_if_needed(). I could find nothing that explicitly says that when running in GC mode, an autorelease pool that has been sent a -drain message is 'no longer valid' (ie, something along the lines of behaving as if it was sent a release message). Nothing I could find in the documentation seems to expressly forbid sending an instantiated NSAutoreleasePool object a -drain message multiple times when running under GC.
The closest thing I could find was near the top of the NSAutoreleasePool class documentation: 'draining a pool ultimately has the effect of deallocating it'. This does little to help us here, though. The context from which this was taken is not terribly clear as to whether or not this applies to GC or non-GC mode. In any case, it is qualified with 'ultimately', which by pedantic dictionary definition means 'not now, but eventually'. Without the 'ultimately' qualification it's unambiguous as to whether or not the the instantiated autorelease pool object has been deallocated, and by induction, that sending additional messages to that pointer will result in undefined behavior.
So, since I can't point to anything authoritative to back this up, it's my opinion that -drain, in non-GC mode, behaves 'exactly' like -release (most likely implemented internally as [self release]). If this is true, you have 'over released' the NSAutoreleasePool object, in which case the problem will go away if you comment out one of the two statements.
Related
I have Util class as follows.
#implementation Util
- (NSString*) getTodayString
{
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// display in 12HR/24HR (i.e. 11:25PM or 23:25) format according to User Settings
[dateFormatter setDateFormat:#"YYYY/MM/dd"];
NSString *now = [dateFormatter stringFromDate:today];
[dateFormatter release]; ///???
[today release]; //???
return now;
}
#end
And I use the class
- (void)awakeFromNib
{
Util *ut = [[Util alloc] init];
NSString* now = [ut getTodayString];
NSLog(#"User's current time in their preference format:%#",now);
[currentTime setObjectValue:now];
[now release]; ///???
[ut release];
}
I'm confused when releasing objects.
In getTodayString ::
Q1. [dataFormatter release] is necessary?
Q2. [today release] is necessary?
I guess I don't need to release them as I didn't alloc myself. If that's true, when those objects are released?
In awakeFromNib ::
Q3. [ut release] is necessary?
Q4. [now release] is necessary?
I guess I have to release ut as I create the object explicitly, but not suer about now object.
How one can determine when is the object is released?
With python/C#/Java one doesn't care about this kind of deallocation of memory anymore. Is it also OK with Objective-C if I don't care about them?
Q1. [dataFormatter release] is
necessary? Q2. [today release] is
necessary?
dataFormatter: yes, you alloc/init'd it.
today: no, it was returned autoreleased from a factory method.
Q3. [ut release] is necessary? Q4.
[now release] is necessary?
The same,
ut: yes, you alloc/init'd it.
now: no, it was returned autoreleased from a factory method.
How one can determine when is the
object is released?
it's released when release is called on it, if autorelease is called, release will be called during the next run of the Autorelease Pool.
Is it also OK with Objective-C if I
don't care about them?
No, it's not ok. If you do not clean up after yourself you will have substantial memory leaks, in the iOS environment that means a quite shutdown of your app. In a Mac app that can lead to eating up a ton of memory and not being a good citizen. This is assuming a non garbage collection environment. Ie most.
I'm guessing the heart of your question is you aren't sure when you are responsible for calling release and when you get an autoreleased object (or rather, when you are responsible for calling release on the object). It's by convention. If you call any method that returns an object that does not contain the words: init/copy then it is not your responsibility to call release. If you retain, you release (There may be some more rules to follow, but that's the first one to really start understanding this, in my opinion). If you ever call alloc/init/copy, then you must call release at some point.
A GREAT teacher is Build & Analyze in Xcode. This will quickly point out where you screwed up and really help to understand what is going on.
Whether or not you care about memory management in objective-c depends on the environment you are using. If you are using garbage collection, you don't have to worry about it, but garbage collection is not enabled by default on the mac and is not available at all on iOS. Basic rules for when something needs to be released:
If the method you get it from starts with alloc or init, or contains the word copy, then you own it and must release it.
If you explicitly retain an object, you own it and must release it.
If the method does not contain alloc, init, or copy, you can assume it has been autoreleased. It will be released automatically at some point in the future, and you need to retain it if you want to use it after the current method returns.
Of course those also depend on any third party code following those rules with when they autorelease returned objects.
The memory management rules are simple and clear. Do not think in terms of retain counts, always think in terms of ownership. When you ask yourself the question “should I release this object?”, ask yourself “do I own it?”. Commit the rules to memory, and eventually they will become second nature.
It is extremely important that you follow the rules. If you ignore them, objects that you don't own may be deallocated before you are done with them (such as assigning objects that you don't own to instance variables, they may become deallocated after the autorelease pool is drained). Also, if you ignore them, you will end up with horrendous memory leaks.
I'm still wrapping my head around some of the nuances of memory management in objective-C, and came up with the following case I'm unsure about:
+ (NSDecimalNumber*)factorial: (NSDecimalNumber *)l {
NSDecimalNumber *index = l;
NSDecimalNumber *running = [NSDecimalNumber one];
for (; [index intValue] > 1; index = [index decimalNumberBySubtracting:[NSDecimalNumber one]]) {
running = [running decimalNumberByMultiplyingBy: index];
}
return running;
}
Here decimalNumberByMultiplyingBy and decimalNumberBySubtracting will be creating a lot of NSDecimalNumbers, which will get autoreleased eventually as I understand it, but I worry until that time the containing program will be hanging unto an awful lot of memory.
Should I be introducing an autorelease pool somewhere? (If so where?) Is that going to have a noticeable effect on performance (when compared to the side effect of so much memory in use)?
Is autoreleasing the right mechanism to use here? Should I look at breaking the loop apart and manually releasing memory as I'm done with it?
It's likely a n00b question, but I'm trying to get a flavour for what the best practice(s) is/are in this situation.
It's good practice to avoid creating a bunch of large autoreleased objects within a single pass of the run loop. You already seem aware of the solutions. You can use non-autoreleased objects and release them when you're done with them. You can also create an autorelease pool for sections of your code that create a large number of autoreleased objects. When an object is autoreleased, it gets released when the enclosing autorelease pool is released/drained. Using an autorelease pool would look like this:
NSAutoReleasePool *subPool = [[NSAutoreleasePool alloc] init];
// Code that generates a bunch of autoreleased objects.
[subPool release];
But, before you do any optimization, run some benchmarks and see if you actually need to optimize. My guess is that the method you've shown won't cause any problems. However, let's say you're trying to apply your method to a set of a million random integers within a single loop. In that case, you might benefit from using an autorelease pool.
Check out Apple's Memory Management Programming Guide for Cocoa for more details.
You could set up an autorelease pool within the loop, but why bother?
You are not going to be able to accumulate that many objects in this loop, because you're computing factorials, and the largest exponent an NSDecimalNumber can have is 127.
You'll get an overflow error before you even get to 100 iterations through the loop.
Note that the main autorelease pool gets emptied every time the application makes a trip through the main run loop, so the autoreleased values are not going to hang around very long.
Best way to determine the answer is to write it a few different ways and test. I don't think this is going to be a problem, though, NSDecimalNumbers are going to max out around ~100!, and 100 NSDecimalNumber objects probably won't make a bit of difference.
Answer to your other questions: In situations where it will matter you can manually release your objects. You can also create an autorelease pool inside that loop. Autorelease is super fast.
while(/*condition*/) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// code goes here
[pool drain];
}
3 correlated questions:
1.Do the code snippets below provide the very same results in terms of memory?
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
bundle=nil;
and
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
NSBundle *bundle=[NSBundle mainBundle];
[pool drain];
pool=nil;
bundle=nil;
2.Why in
NSBundle *bundle=[[NSBundle alloc] init];
[bundle release];
the retainCount of bundle is 1, not 0?
3.Which is recommended: always use class methods, or always gain ownership by using alloc?
Thanks.
Yes, those should be equivalent in terms of memory management, from the developer's point of view. The frameworks might be doing something behind the scene to hang on to [NSBundle mainBundle], but that's not your concern.
Ignore retainCount. waves hand That's not the method you're looking for. Once you have relinquished ownership of an object, either by invoking release or autorelease, then it is invalid (bad practice) to send more messages to that object. In your example, you alloc an NSBundle, so you own it. That means it has a +1 retain count (I say +1, because it's relative). When you release the bundle, it now has a "0" retain count, which means you no longer own this object (despite whether or not it may still exist in memory), which means you should not send messages to it, under penalty of stuff blowing up in your face.
What's recommended is to use whatever's appropriate for the situation. If you just need a temporary object, then using a class method that returns an autoreleased object is probably going to be just fine. If you need to be absolutely sure that the object isn't going to go away while you're using it, then you can use an alloc/init approach (or retain an autoreleased object) and then just release it when you're done.
In the second example you will create 1 extra object (the NSAutorealeasePool) and because of that the two are not exactly the same in terms of memory. But after the code runs I believe the memory will return to the same state in both examples. I am not really sure but I believe that in the second example bundle is an autoreleased object, so when the pool is drained it gets released.
I believe that when the object gets dealloc'ed the retainCount isn't changed.
It is usually recommended to avoid class methods when you create a lot of temporary objects because they won't get released until the next AutoreleasePool drain is called (and if you don't have an AutoreleasePool inside your method it won't happen for sure until you return from your method - and maybe even later). Otherwise you should use the one that feels better for you. I personally prefer allocating them. It is also important to remember that if you want the autoreleased object (the one returned from a class method) to stick around even after you return from the function to retain it.
I have a problem with the memory management in Objective-C. Say I have a method that allocates an object and stores the reference to this object as a member of the class. If I run through the same function a second time, I need to release this first object before creating a new one to replace it. Supposing that the first line of the function is:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
This means that a different auto-release pool will be in place. The code to allocate the object is as follows:
if (m_object != nil)
[m_object release];
m_object = [[MyClass alloc] init];
[m_object retain];
The problem is that the program crashes when running the last line of the method:
[pool release];
What am I doing wrong ? How can I fix this ?
Regards
Alan
First get a general understanding of the objective c memory management. You are confusing a lot of different things here. For example you don't have to retain the m_object since alloc already sets up the retain count with 1. Also normally you dont release you AutoReleasePool when you release a object. Like I said look up the documentation for memory management (pretty good actually).
Autorelease pools handle objects that have been specifically autoreleased
Example:
[object autorelease];
You have to have at least one NSAutoreleasePool in your program in case some code attempts to autorelease an object. If this is your only NSAutoreleasePool then releasing the pool maybe causing your problems.
I am calling a function repeatedly with a loop, and the loop runs inside of a thread. The thread has an autorelease pool.
I have the following code inside that function:
NSXMLDocument* undoXML;
NSData* undoData = [NSData dataWithContentsOfFile:undoFilePath];
undoXML = [[NSXMLDocument alloc] initWithData:undoData options:NSXMLDocumentTidyXML error:&err];
NSData* undoData2;
undoData2 = [undoXML XMLData];
[undoData2 release];
[undoXML release];
I'm getting the following strange results:
My program is leaking memory every time this function is called by the loop.
When I add the following code to the function:
NSData* undoData3;
undoData3 = [undoXML XMLData];
[undoData3 release];
My program leaks even more memory than before.
I'm really confused and I badly need help figuring out what's going on. Maybe my autorelease pool isn't working correctly? Why is this happening?
Are you sure it is leaking? Or is it simply growing in size?
What does your loop look like and how is the autorelease pool integrated into it?
The autorelease pool must be inside the loop or your loop will just build up tons of memory over time. That the leaks instrument doesn't show leaks indicates that you have violated the memory management rules or your loop is incorrect.
Try running Instruments on your project w/ the leak detection settings. This should identify exactly where your leak is occurring (even in the system libraries).
Run -> Run With Performance Tool -> Leaks
undoData should be preset to be autoreleased (according to naming convention dataWithContentsOfFile: returns an autoreleased object). But unless you have your own autorelease pool, nothing that is set to autorelease will actually be deallocated until the active pool is drained (i.e. sometime after your function returns).
Your thread may have its own autorelease pool, but unless you are creating one inside your own function, nothing will be deallocated until after your function exits.
If you want to trigger the draining of autoreleased objects in the middle of a function (say once per loop), you need to manage your own autorelease pool.
while(looping) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// do stuff that produces autoreleased objects
[pool drain];
}
Also, per cobbal's comment on your question, it looks like you should not be releasing undoData2 (or undoData3). Based on the naming convention -[NSXMLDocument XMLData] should be returning an autoreleased object.
If you have access to the source code of the NSData class you should look at what objects are being instantiated when undoData3 is created. I say this because you create the object and immediately destroy it. The issue must be that memory is being allocated inside the class but not being deallocated in it's destructor.