Objective C ARC unable to free memory - ios

According to the leaks tool, the following code results in a memory leak:
- (NSString *)emojiWithCode:(int)code {
int sym = EMOJI_CODE_TO_SYMBOL(code);
__block __weak NSString *result = [[NSString alloc] initWithBytes:&sym length:sizeof(sym) encoding:NSUTF8StringEncoding];
return result;
}
I tried to free the sym with free(&sym) but at that time the following error comes up:
malloc: *** error for object 0x27d2e60c: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug
How is this causing a leak if it is not allocated?
How can I free this memory correctly and solve the issue?
EMOJI_CODE_TO_SYMBOL is this
#define EMOJI_CODE_TO_SYMBOL(x) ((((0x808080F0 | (x & 0x3F000) >> 4) | (x & 0xFC0) << 10) | (x & 0x1C0000) << 18) | (x & 0x3F) << 24);
I have attached the leaks tool screenshot as well.

Instruments has no way of knowing why this object leaked, so it's only showing you the line of code where the leaked object was initially allocated. This line of code (once you remove the __block and __weak) is fine, so you have to dig in further to find out why this object leaked.
Bottom line, you don't have to do anything with this line of code, but rather you need to figure out where this string was subsequently used in order to identify why it leaked. Most likely, the object that used this string itself leaked (e.g. a strong reference cycle or something like a repeating timer that is holding on to the leaked object). And because that object leaked, this string also leaked. So, take your analysis up a level, and look where this string was used and figure out why it didn't get released.
I'd suggest you check out WWDC 2012 video iOS App Performance: Memory for a tutorial on how to use Instruments to guide your research to identify the ultimate source of the leak.
Also, it's often worth doing a static analysis (choose "Analyze" on the Xcode "Product" menu), as in some situations it can identify sources of problems. Make sure the static analyzer gives you a clean bill of health before diving into Instruments. This is admittedly more useful in non-ARC code, but sometimes it can identify issues.

Related

ARC with cocos2d causing unbounded heap growth and eventual memory crash?

I'm trying to track down a memory-related crash in my game. The exact error, if I happen to catch it while attached to a debugger varies. One such error message is:
Message from debugger: Terminated due to memory issue.
No crash report is generated. Here's a screenshot from the XCode7 Memory Report as I play on my iPhone6; after about 10 minutes it will crash, as I enter into the ~600MB+ range:
Running generational analysis with Instruments I've found that playing through battles appears to create unbounded persistent memory growth; here you can see what happens as I play through two battles:
What is confusing is that the allocations revealed by the twirl-down are pretty much every single bit of allocated memory in the whole game. Any read of a string from a dictionary, any allocation of an array, appears in this twirl-down. Here's a representitive example from drilling into an NSArray caller-analysis:
At this point, it occurs to me I started this project using cocos2d-iphone v2.1 a couple of years ago, and I started an ARC project despite using a pre-ARC library. I'm wondering if I'm just now realizing I configured something horribly, horribly wrong. I set the -fno-objc-arc flag on the cocos2d files:
Either that, or I must have done something else very very stupid. But I'm at a loss. I've checked some of the usual culprits, for example:
Put a NSLog in dealloc on my CCScene subclass to make sure scenes were going away
Made sure to implement cleanup (to empty cached CCNodes) and call super in my sublcasses
Dumped the cocos2d texture cache size, and checked it was not growing unbounded
Added low memory warning handlers, doing things like clearing the cocos2d cache
I've also been pouring over the Apple instruments documentation, in particular this link explains the steps I took to create the above generational analysis.
Update
Here's another representative example, this time in tree format. You can see that I have a CCScheduler which called an update function which triggered the UI to draw a sprite. The last time you see my code, before it delves into cocos2d code, is the highlighted function, the code for which I've also pasted below.
+ (instancetype)spriteAssetSource:(NSString*)assetName {
if(!assetName.length) {
return nil;
}
BOOL hasImageSuffix = [assetName hasSuffix:EXT_IMG];
NSString *frameName = hasImageSuffix ? [assetName substringToIndex:assetName.length-EXT_IMG.length] : assetName;
NSString *hdFrameName = [NSString stringWithFormat:#"%#%#",frameName,EXT_HD];
// First, hit up the sprite sheets...
if([[CCSpriteFrameCache sharedSpriteFrameCache] hasSpriteFrameName:hdFrameName]) {
CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:hdFrameName];
return [[self alloc] initWithSpriteFrame:frame];
}
// No sprite sheet? Try the assets.
else {
NSString *assetFp = hasImageSuffix ? assetName : [NSString stringWithFormat:#"%#%#",assetName,EXT_IMG];
return [[self alloc] initWithFile:assetFp];
}
}
What's so weird about this is that the captured memory is just the simple line to check if the file name is in the cocos2d cache:
- (BOOL)hasSpriteFrameName:(NSString*)name {
return [_spriteFrames.allKeys containsObject:name];
}
Yet this simple function shows up all over the place in these traces...
What it feels like is that any locally-scoped variable I create and pass into cocos2d gets its retain count incremented, and thus never deallocates (such as the case with both hdFrameName and other variables above).
Update 2
While it's no surprise that the CCScheduler sits at the top of the abandoned objects tree, what is surprising is that some of the objects are completely unrelated to cocos2d or UI. For example, in the highlighted row, all I've done is call a function on AMLocalPlayerData that does a [NSDate date]. The entire line is:
NSTimeInterval now = [NSDate date].timeIntervalSince1970;
It seems absurd that the NSDate object could be retained somehow here, yet that seems to be what Instruments is suggesting...
Update 3
I tried upgrading my version of cocos2d to 2.2, the last version to exist in the repository. The issue persists.

iPhone Memory management for a deallocated password (Malloc Scribble in production?, fill with zeroes deallocated memory?)

I'm doing some research on how iPhone manage the heap and stack but it's very difficult to find a good source of information about this. I'm trying to trace how a password is kept in memory, even after the NSString is deallocated.
As far as I can tell, an iPhone will not clear the memory content (write zeros or garbage) once the release count in ARC go down to 0. So the string with the password will live in memory until that memory position is overridden.
There's a debug option in Xcode, Malloc Scribble, to debug memory problems that will fill deallocated memory with 0x55, by enabling/disabling this option (and disabling Zombies), and after a memory dump of the simulator (using gcore) I can check if the content has been replaced in memory with 0x55.
I wonder if this is something that can be done with the Apple Store builds, fill deallocated memory with garbage data, if my assumption that iPhone will not do that by default is correct or not, or if there's any other better option to handle sensitive data in memory, and how it should be cleared after using it (Mutable data maybe? write in that memory position?)
I don't think that there's something that can be done on the build settings level. You can, however, apply some sort of memory scrubbing yourself by zeroing the memory (use memset with the pointer to your string).
As #Artal was saying, memset can be used to write in a memory position. I found this framework "iMAS Secure Memory" that can be useful to handle this:
The "iMAS Secure Memory" framework provides a set of tools for
securing, clearing, and validating memory regions and individual
variables. It allows an object to have it's data sections overwritten
in memory either with an encrypted version or null bytes
They have a method that it should be useful to clear a memory position:
// Return NO if wipe failed
extern inline BOOL wipe(NSObject* obj) {
NSLog(#"Object pointer: %p", obj);
if(handleType(obj, #"", &wipeWrapper) == YES) {
if (getSize(obj) > 0){
NSLog(#"WIPE OBJ");
memset(getStart(obj), 0, getSize(obj));
}
else
NSLog(#"WIPE: Unsupported Object.");
}
return YES;
}

Why this doesn't crash? [duplicate]

This question already has answers here:
Objective-C autorelease pool not releasing object
(2 answers)
Why can I send messages to a deallocated instance of NSArray?
(2 answers)
Closed 9 years ago.
Why the second line in the loop (the a.retainCount one) won't crash (due to bad access) ?
NSArray* a0 = #[[NSMutableString stringWithString:#"a"]];
NSArray * arr = [NSArray arrayWithObject:a0];
[a0 release];[a0 release];
for (NSArray* a in arr)
{
//NSLog(#"%d", (a == a0) );
NSLog(#"RC: %d", a.retainCount);
}
but it would crash if the first line in loop (a == a0 one) is un-commented.
This would definitely crash when the autorelease pool is drained, but I am specifically asking about the second line in loop, not afterwards.
Can anyone please explain?
Please review http://www.whentouseretaincount.com/
Sending a message to a deallocated object is undefined behavior. It may crash, it may not.
In this case, it isn't crashing because the memory that contained the object hasn't been overwritten by something else. If you were to turn on Malloc Scribble, it'd crash. That call to NSLog() coincidentally causes the memory to be scribbled upon, causing the crash.
retainCount can never return 0 exactly because messaging a deallocated object is undefined behavior. The system doesn't bother decrementing the RC to 0 because the object is no longer viable anyway.
I'm curious within what context this question came up? Are you using a tutorial or class materials that use retainCount?
It isn't always a segmentation fault for the same reason the runtime doesn't decrement the retain count to 0; efficiency.
To make it a guaranteed segmentation fault would mean wasting a few cycles writing bogus values to the memory (or decrementing the retain count).
As it is, free() just marks the memory as being available for future malloc()s. It doesn't modify the contents of the memory in any way, hence the undefined behavior.
This could crash any time. Likely the first line in the loop triggered the memory at the dangling pointer "a" allocated for other use. So when "a" is referenced on the second line, anything could happen.
If you turn on the XCode options in "Scheme -> Diagnostics -> Memory Management", this may crash immediately.

Can't figure out memory leak testing with simulator and in general

EDIT: guys, my question was about using the Instruments to see leaks, and the code as an example and side question, but you answered the side question and not the main problem.... Thank you for the answers, but I really need to find out how to work the Instruments with the simulator....
I am learning IOS development, In one of the codes I'm studying i think there is huge memory leak so I've tried learning how to use instruments. As i am learning right now, I am trying to use instruments with the simulator, but all the manuals i found are for connecting to a device and then using instruments and not with the simulator. every thing I've tried doesn't show any leaks in Instruments.
The app doesn't crash because i am guessing the memory leak is not that big, but when i am adding the following code it does crash, why is that, Even when i added the release every time, still crashes....what is wrong with the simulator? or with the code? working with xcode3, not 4.
for (int i = 0; i < 1000000; i++) {
NSString *testLeak = [[NSString alloc] initWithString:#"test1223"];
NSLog(#"%#",testLeak);
[testLeak release];
}
And again, the app crashes and the simulator doesn't show any leaks, even when i put the "attach process" on "iPhone simulator".
NSString *testLeak = [[NSString alloc] initWithString:#"test1223"];
The problem is that you are not actually allocating anything. NSString is internally smart enough to recognize that the above expression does not need to allocate anything because the constant string #"test1223" can neither mutate nor ever be deallocated. Thus, it just returns that string.
If you were to NSLog(#"%p", testLeak); you'd see the same address over and over.
Change the NSString to NSMutableString and you'll likely see the thousands of copies. Maybe; NSMutableString could be optimized to just point to the immutable copy until a mutation operation is performed (implementation detail). Or you could allocate an instance of some class of your own creation.
Keep in mind that Leaks doesn't necessarily show you all leaks; it can't because of the way it works.
For this kind of analysis, Heapshot analysis is very effective.
If it is crashing as described, please (a) post the crash log and (b) file a bug with your app (built for the simulator) attached to http://bugreport.apple.com/.
In general Instruments + Simulator will not be terribly useful; the simulator is only an approximation of what is running on the device.
[something release] doesn't actually free the memory the instant it is called - it just decreases the reference count of an object. If the count is 0, a [something dealloc] is called, and that frees the memory. I guess you are allocating memory faster than the system can free it... besides, doing 1.000.000 allocs in rapid succession instead of single huge one is probably as bad a coding practice as they come...
It may be that some stuff is getting autorelease'd, and that is using a ton of the heap. Try changing your code to this:
for (int i = 0; i < 1000000; i++) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *testLeak = [[NSString alloc] initWithString:#"test1223"];
NSLog(#"%#",testLeak);
[testLeak release];
[pool drain];
}
Thank you all, I actualy Found the answer around 4 am yestorday...
when you want to test leaks on the emulator:
rum -> run with Performance Tool ->Leaks
If you select the simulator on the top right as the device to run the app on, It will lounch the simulator and the instruments and start the leak recorder, all in one click....
Have fun :-)
Erez

EXC_BAD_ACCESS signal received

When deploying the application to the device, the program will quit after a few cycles with the following error:
Program received signal: "EXC_BAD_ACCESS".
The program runs without any issue on the iPhone simulator, it will also debug and run as long as I step through the instructions one at a time. As soon as I let it run again, I will hit the EXC_BAD_ACCESS signal.
In this particular case, it happened to be an error in the accelerometer code. It would not execute within the simulator, which is why it did not throw any errors. However, it would execute once deployed to the device.
Most of the answers to this question deal with the general EXC_BAD_ACCESS error, so I will leave this open as a catch-all for the dreaded Bad Access error.
EXC_BAD_ACCESS is typically thrown as the result of an illegal memory access. You can find more information in the answers below.
Have you encountered the EXC_BAD_ACCESS signal before, and how did you deal with it?
From your description I suspect the most likely explanation is that you have some error in your memory management. You said you've been working on iPhone development for a few weeks, but not whether you are experienced with Objective C in general. If you've come from another background it can take a little while before you really internalise the memory management rules - unless you make a big point of it.
Remember, anything you get from an allocation function (usually the static alloc method, but there are a few others), or a copy method, you own the memory too and must release it when you are done.
But if you get something back from just about anything else including factory methods (e.g. [NSString stringWithFormat]) then you'll have an autorelease reference, which means it could be released at some time in the future by other code - so it is vital that if you need to keep it around beyond the immediate function that you retain it. If you don't, the memory may remain allocated while you are using it, or be released but coincidentally still valid, during your emulator testing, but is more likely to be released and show up as bad access errors when running on the device.
The best way to track these things down, and a good idea anyway (even if there are no apparent problems) is to run the app in the Instruments tool, especially with the Leaks option.
A major cause of EXC_BAD_ACCESS is from trying to access released objects.
To find out how to troubleshoot this, read this document:
DebuggingAutoReleasePool
Even if you don't think you are "releasing auto-released objects", this will apply to you.
This method works extremely well. I use it all the time with great success!!
In summary, this explains how to use Cocoa's NSZombie debugging class and the command line "malloc_history" tool to find exactly what released object has been accessed in your code.
Sidenote:
Running Instruments and checking for leaks will not help troubleshoot EXC_BAD_ACCESS. I'm pretty sure memory leaks have nothing to do with EXC_BAD_ACCESS. The definition of a leak is an object that you no longer have access to, and you therefore cannot call it.
UPDATE:
I now use Instruments to debug Leaks. From Xcode 4.2, choose Product->Profile and when Instruments launches, choose "Zombies".
An EXC_BAD_ACCESS signal is the result of passing an invalid pointer to a system call. I got one just earlier today with a test program on OS X - I was passing an uninitialized variable to pthread_join(), which was due to an earlier typo.
I'm not familiar with iPhone development, but you should double-check all your buffer pointers that you're passing to system calls. Crank up your compiler's warning level all the way (with gcc, use the -Wall and -Wextra options). Enable as many diagnostics on the simulator/debugger as possible.
In my experience, this is generally caused by an illegal memory access. Check all pointers, especially object pointers, to make sure they're initialized. Make sure your MainWindow.xib file, if you're using one, is set up properly, with all the necessary connections.
If none of that on-paper checking turns anything up, and it doesn't happen when single-stepping, try to locate the error with NSLog() statements: sprinkle your code with them, moving them around until you isolate the line that's causing the error. Then set a breakpoint on that line and run your program. When you hit the breakpoint, examine all the variables, and the objects in them, to see if anything doesn't look like you expect.I'd especially keep an eye out for variables whose object class is something you didn't expect. If a variable is supposed to contain a UIWindow but it has an NSNotification in it instead, the same underlying code error could be manifesting itself in a different way when the debugger isn't in operation.
I just spent a couple hours tracking an EXC_BAD_ACCESS and found NSZombies and other env vars didn't seem to tell me anything.
For me, it was a stupid NSLog statement with format specifiers but no args passed.
NSLog(#"Some silly log message %#-%#");
Fixed by
NSLog(#"Some silly log message %#-%#", someObj1, someObj2);
The 2010 WWDC videos are available to any participants in the apple developer program.
There's a great video: "Session 311 - Advanced Memory Analysis with Instruments" that shows some examples of using zombies in instruments and debugging other memory problems.
For a link to the login page click HERE.
Not a complete answer, but one specific situation where I've received this is when trying to access an object that 'died' because I tried to use autorelease:
netObjectDefinedInMyHeader = [[[MyNetObject alloc] init] autorelease];
So for example, I was actually passing this as an object to 'notify' (registered it as a listener, observer, whatever idiom you like) but it had already died once the notification was sent and I'd get the EXC_BAD_ACCESS. Changing it to [[MyNetObject alloc] init] and releasing it later as appropriate solved the error.
Another reason this may happen is for example if you pass in an object and try to store it:
myObjectDefinedInHeader = aParameterObjectPassedIn;
Later when trying to access myObjectDefinedInHeader you may get into trouble. Using:
myObjectDefinedInHeader = [aParameterObjectPassedIn retain];
may be what you need. Of course these are just a couple of examples of what I've ran into and there are other reasons, but these can prove elusive so I mention them. Good luck!
I find it useful to set a breakpoint on objc_exception_throw. That way the debugger should break when you get the EXC_BAD_ACCESS.
Instructions can be found here DebuggingTechniques
Just to add another situation where this can happen:
I had the code:
NSMutableString *string;
[string appendWithFormat:#"foo"];
Obviously I had forgotten to allocate memory for the string:
NSMutableString *string = [[NSMutableString alloc] init];
[string appendWithFormat:#"foo"];
fixes the problem.
Another method for catching EXC_BAD_ACCESS exceptions before they happen is the static analyzer, in XCode 4+.
Run the static analyzer with Product > Analyze (shift+cmd+B).
Clicking on any messages generated by the analyzer will overlay a diagram on your source showing the sequence of retains/releases of the offending object.
Use the simple rule of "if you didn't allocate it or retain it, don't release it".
Run the application and after it fails (Should display "Interrupted" rather than "EXC_BAD_ACCESS"... Check the Console (Run > Console)... There should be a message there now telling what object it was trying to access.
I've been debuging, and refactoring code to solve this error for the last four hours. A post above led me to see the problem:
Property before:
startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
.
.
.
x = startPoint.x - 10; // EXC_BAD_ACCESS
Property after:
startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];
Goodbye EXC_BAD_ACCESS
Hope you're releasing the 'string' when you're done!
I forgot to return self in an init-Method... ;)
This is an excellent thread. Here's my experience: I messed up with the retain/assign keyword on a property declaration. I said:
#property (nonatomic, assign) IBOutlet UISegmentedControl *choicesControl;
#property (nonatomic, assign) IBOutlet UISwitch *africaSwitch;
#property (nonatomic, assign) IBOutlet UISwitch *asiaSwitch;
where I should have said
#property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
#property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
#property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;
I encountered EXC_BAD_ACCESS on the iPhone only while trying to execute a C method that included a big array. The simulator was able to give me enough memory to run the code, but not the device (the array was a million characters, so it was a tad excessive!).
The EXC_BAD_ACCESS occurred just after entry point of the method, and had me confused for quite a while because it was nowhere near the array declaration.
Perhaps someone else might benefit from my couple of hours of hair-pulling.
Forgot to take out a non-alloc'd pointer from dealloc. I was getting the exc_bad_access on my rootView of a UINavigationController, but only sometimes. I assumed the problem was in the rootView because it was crashing halfway through its viewDidAppear{}. It turned out to only happen after I popped the view with the bad dealloc{} release, and that was it!
"EXC_BAD_ACCESS" [Switching to process 330] No memory available to program now: unsafe to call malloc
I thought it was a problem where I was trying to alloc... not where I was trying to release a non-alloc, D'oh!
How i deal with EXC_BAD_ACCESS
Sometimes i feel that when a EXC_BAD_ACCESS error is thrown xcode will show the error in the main.m class giving no extra information of where the crash happens(Sometimes).
In those times we can set a Exceptional Breakpoint in Xcode so that when exception is caught a breakpoint will be placed and will directly intimate the user that crash has happened in that line
NSAssert() calls to validate method parameters is pretty handy for tracking down and avoiding passing nils as well.
I just had this problem. For me the reason was deleting a CoreData managed object ans trying to read it afterwards from another place.
I've been debuging, and refactoring code to solve this error for the last four hours. A post above led me to see the problem:
Property before:
startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
x = startPoint.x - 10; // EXC_BAD_ACCESS
Property after:
startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];
Goodbye EXC_BAD_ACCESS
Thank you so much for your answer. I've been struggling with this problem all day. You're awesome!
Just to add
Lynda.com has a fantastic DVD called
iPhone SDK Essential Training
and Chapter 6, Lesson 3 is all about EXEC_BAD_ACCESS and working with Zombies.
It was great for me to understand, not just the error code but how can I use Zombies to get more info on the released object.
To check what the error might be
Use NSZombieEnabled.
To activate the NSZombieEnabled facility in your application:
Choose Project > Edit Active Executable to open the executable Info window.
Click Arguments.
Click the add (+) button in the “Variables to be set in the environment” section.
Enter NSZombieEnabled in the Name column and YES in the Value column.
Make sure that the checkmark for the NSZombieEnabled entry is selected.
I found this answer on iPhoneSDK
I realize this was asked some time ago, but after reading this thread, I found the solution for XCode 4.2:
Product -> Edit Scheme -> Diagnostics Tab -> Enable Zombie Objects
Helped me find a message being sent to a deallocated object.
When you have infinite recursion, I think you can also have this error. This was a case for me.
Even another possibility: using blocks in queues, it might easily happen that you try to access an object in another queue, that has already been de-allocated at this time. Typically when you try to send something to the GUI.
If your exception breakpoint is being set at a strange place, then this might be the cause.
I got it because I wasn't using[self performSegueWithIdentifier:sender:] and -(void) prepareForSegue:(UIstoryboardSegue *) right
Don't forget the # symbol when creating strings, treating C-strings as NSStrings will cause EXC_BAD_ACCESS.
Use this:
#"Some String"
Rather than this:
"Some String"
PS - typically when populating contents of an array with lots of records.
XCode 4 and above, it has been made really simple with Instruments. Just run Zombies in Instruments. This tutorial explains it well: debugging exc_bad_access error xcode instruments

Resources