Why iOs code is using so much memory and CPU - ios

I have a some permutation/combination code that is iterating through 20 objects taking 5 at a time. When the list meets some criteria I print the objects that make up that list. Needless to say the loop is rather large. I place all of the combinations in an NSMutableArray inside of the loop. Once the objects have been added and pass/fail the test, I remove all of the object from the array. (Psuedo code below).
-(void)CreateCombinations
{
NSMutableArray *Combinations = [[NSMutableArray alloc] init];
#autoreleasepool {
NSArray *objectsList = [[NSArray alloc] initWithObjects:
#“Lisa”,#“Kevin”,…nil];
} //autorelease pool
while(!Finished)
{
Combinations = [self getNextCombo: Combinations]
if (goodCombination)
[self printCombos:Combinations]
[Combinations removeAllObject];
}
}
While monitoring the debug session, CPU and memory are at capacity. I am sure the looping is coming into play. I don't believe that I am reallocating the 'Combinations' Array for every iteration. If I am, is there something that I can do to make sure that it is properly deallocated or released before the next iteration of the loop?
When I add the #autorelease (which is before the loop) I get a "use of undeclared identifier error".

The code you've shown is completely fake so it's impossible to guess what your real code is doing wrong. But if you are using memory because you are piling up autoreleased objects during a loop, wrap the interior of the loop in an #autoreleasepool block:
while (...) {
#autoreleasepool {
// do stuff
}
}
The idea is to release the temporarily used memory every time through the loop.

Related

Safely perform changes to NSMutableArray

What can cause an assignment or change to an NSMutableArray to crash?
I have a mutable array containing custom objects, and I consistently keep no more than the 3 latest objects in it, the rest are removed. I started calling
[myArray insertObject:newObject atIndex:0];
if (myArray.count > 3)
[myArray removeLastObject]; // Crash
But whenever I do this too fast, the last line causes an exception-less crash.
I know that you are not allowed to add or remove objects of an array while it is being enumerated, but I do not enumerate myArray anywhere unless calling count on it performs an implicit enumeration. I also tried doing this:
NSMutableArray *tmp = [myArray mutableCopy];
[tmp removeLastObject];
myArray = tmp; // Crash
But the same thing happens, it crashes on the last line. Again, this works perfectly fine when doing it slowly. The action itself is being called when a user taps a button, and when tapping it too fast, it crashes every time.
EDIT:
I should add that all of this is being run inside the cellForItemAtIndexPath method of a UICollectionView.
First, could you please post the crash message. It would be nice to know what error you are actually seeing.
I wonder what would happen if you switched to immutable arrays. Switch myArray to being an NSArray * and use the following.
myArray = [self updatedArray:myArray withObject:newObject];
Where -updatedArray:withObject: is
- (NSArray *)updatedArray:(NSArray *)array withObject:(id)object {
switch (array.count) {
case 0: return #[object];
case 1: return #[object, array[0]];
default: return #[object, array[0], array[1]];
}
}
Or better for testing
NSArray *temp = [self updatedArray:myArray withObject:newObject];
myArray = temp; // I assume the crash will be here!
If the code crashed at my comment, then deallocating myArray is causing the crash. My guess is that one of the items in the array is pointing to bad memory (a zombie or some such thing).
I can think of two possible reasons for the crash:
1) The array is being accessed/mutated from multiple threads
2) An object inside the array was over-released somewhere, causing it to be deallocated while still living inside the array.
Short answer: try profiling your app in Instruments, and select the "Zombies" instrument. When the crash happens, you just might get a zombie alert, in which case you can get a back-log of everything that led up to your memory getting stomped over.
I think the root cause is this variable is accessed from multiple threads at the same time.
You can use this when access the array
#synchronized(self) {
//Your accessed code here
}

Objective-C Memory Issue with NSArray literal using NSNumber object

I have started out with Objective-C recently and trying to understand the memory management. I came across a peculiar problem yesterday which was causing a memory leak of over 150MB! I traced it down to a piece of code that was creating NSArray literal of NSNumbers. I managed to solve the issue using NSMutableArray (using addObject), but I haven't been able to grasp the concept as to why one method works and the other doesn't. I would love for someone with a better understanding of the memory management to explain the concept behind it so that I can avoid such mistakes in the future.
To better illustrate my question, let me also provide the code snippets. So for instance, I have a function that creates a NSArray of few NSNumbers and returns it and it gets called many times:
-(NSArray *)getNSNumberArray
{
float num1 = 23.56;
float num2 = 75.34;
float num3 = 223.56;
NSArray *numArray = #[[NSNumber numberWithFloat:num1], [NSNumber numberWithFloat:num2], [NSNumber numberWithFloat:num3]];
return numArray;
}
-(void)causeMemoryLeak
{
for (int i = 0; i < 2000000; i++)
{
NSArray *recieverArray = [self getNSNumberArray];
}
}
This results in memory being occupied to be more than 200MB on an iphone6. However if I change my function to be:
-(NSArray *)getNSNumberArray
{
float num1 = 23.56;
float num2 = 75.34;
float num3 = 223.56;
NSMutableArray *numMutableArray = [[NSMutableArray alloc] init];
NSNumber *nsNumber1 = [NSNumber numberWithFloat:num1];
NSNumber *nsNumber2 = [NSNumber numberWithFloat:num2];
NSNumber *nsNumber3 = [NSNumber numberWithFloat:num3];
[numMutableArray addObject:nsNumber1];
[numMutableArray addObject:nsNumber2];
[numMutableArray addObject:nsNumber3];
return numMutableArray;
}
-(void)causeMemoryLeak
{
for (int i = 0; i < 2000000; i++)
{
NSArray *recieverArray = [self getNSNumberArray];
}
}
This does not cause any memory issues.
Maybe I am missing something very obvious, but still cant figure out the reason behind this. Would really appreciate the help on this. There could also be better ways of doing it, and such answers are welcome but basically I am looking for an explanation behind it.
Many thanks in advance!
Attaching links to screenshots showing the memory allocation on device (iphone 6) (I can not attach images here as of now, so have to provide links)
Approach 1 Memory Allocation (memory is retained and not freed up): https://drive.google.com/open?id=0B-a9WJSBuIL4bTR5RTVuaWpqYkE&authuser=0
Approach 2 Memory Allocation (memory is freed up and there is no surge in memory allocation as well): https://drive.google.com/open?id=0B-a9WJSBuIL4QzQzbGYyQzZDdW8&authuser=0
I tried your code because I really didn't found any reason for memory leak and there is no memory leak.
When you use the regular array, the device runs all the code, and releases the memory only at the end. This causing the heap to alloc 250 MB, and release them at the end.
If you use the mutable array, the device releases the previous array before creating the new one, so there is no point with to many allocation.
I guess that the different may be caused by run time complexity of the called function in the loop.
As you are saying, only one approach is causing surge in memory, it does not seem so. According to the documentation, NSMutableArray uses slightly more memory because it can change size, it can't store the contents inside the object and must store a pointer to out of line storage as well as the extra malloc node for the storage.
In both the approaches, memory is freed up instantly, there is no issue with me.
Update 1 :
I have noticed that if you use the array, for example if you log the array, the memory is freed up instantly in your first approach. It is happening as you do not use that array. It solves your problem.Try this code :
-(NSArray *)getNSNumberArray
{
float num1 = 23.56;
float num2 = 75.34;
float num3 = 223.56;
NSArray *numArray = #[[NSNumber numberWithFloat:num1], [NSNumber numberWithFloat:num2], [NSNumber numberWithFloat:num3]];
return numArray;
}
-(void)causeMemoryLeak
{
for (int i = 0; i < 2000000; i++)
{
NSArray *recieverArray = [self getNSNumberArray];
NSLog(#"%#", recieverArray);
}
}
First, you need to read up on "autorelease" and "autorelease pools". Objects often are kept inside an autorelease pool and only disappear when the autorelease pool disappears. So a loop iterating two million times without using an autorelease pool is a bad, bad idea. You don't actually have a memory leak, the objects will all be released some time after the method returns.
Most methods returning objects return autoreleased objects, but the result of [[xxx alloc] init] is not autoreleased, so there you have the difference. But also ARC is quite clever, and if a method returns an autoreleased object and the caller immediately retains the object, the object will not actually be added to the autorelease pool. That's what happened when the object was passed to NSLog; in order to do that, it had to be retained first. No autorelease pool. In your code, the object was never used, so that optimisation didn't happened.
Of course your code is really useless, so you were punished for writing useless code.

Why this simple app with ARC leaks?

So I'm relative new to objC programming. But not to C. In a more complicated app I think I have a memory leaks. I've programmed this just for make some tests. The app is very simple: it store in a MutableArray a series of integer that rappresent timers scheduled. The app has one NSTimer in the current runloop that check every second if it is the right time to ring comparing a counter with the right element of the MutableArray. Everything works, but memory in debug panel grow up, grow up, grow up…
I've try some variants but something still missing for me about ARC. I simply don't understand, since ARC is NOT a garbage collector, why memory grow and what I do wrong.
Here is the code:
-(id)initWithLabel:(UILabel *)label {
self = [super init];
self.list = [[mtAllarmList alloc]init];
self.label = label;
return self;
}
My class init function. I pass a label reference (weak beacause it is own by viewcontroller) to my class. I also allocate and init the class mtAllarmList that contain the MutableArray and other information (in the original app, file to play, volumes, eccetera).
-(void)ClockRun {
NSMethodSignature * signature = [mtClockController instanceMethodSignatureForSelector:#selector(check)];
NSInvocation * selector = [NSInvocation invocationWithMethodSignature: signature];
[selector setTarget:self];
[selector setSelector:#selector(check)];
[[NSRunLoop currentRunLoop] addTimer: self.time = [NSTimer scheduledTimerWithTimeInterval:1
invocation:selector
repeats:YES]
forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] runUntilDate:[[NSDate alloc]initWithTimeIntervalSinceNow: 30]];
}
ClockRun: is the method the app call to start everything. It simply start the timer that fires every second to check:
-(void)check {
self.counter++;
int i = [self.list check:self.counter];
if(i == 1) {
[self writeAllarmToLabel:self.label isPlayingAllarmNumber:self.counter];
}
else if (i == 2) {
[self writeAllarmToLabel:self.label theString: #"Stop"];
[self.time invalidate];
self.counter = 0;
}
else {
[self writeAllarmToLabel:self.label theString:[[NSString alloc]initWithFormat:#"controllo, %d", self.counter]];
}
NSLog(#"controllo %d", self.counter);
}
Check: simply reacts to the return value of [list check: int] methods of mtAllarmList. It returns 1 if timer must ring, 0 if not, and 2 if the sequence ends. In that case self.counter will be set to 0 and the NSTimer will be invalidate.
-(id)init {
self = [super init];
self.arrayOfAllarms = [[NSMutableArray alloc]initWithCapacity:0];
int i;
for(i=1;i<=30;++i) {
[self.arrayOfAllarms addObject: [[NSNumber alloc]initWithInt:i*1]];
}
for(NSNumber * elemento in self.arrayOfAllarms)
NSLog(#"ho creato un array con elemento %d", [elemento intValue]);
return self;
}
In mtAllarmList init method simulates the costruction an array (I've try a variety of patterns) and log all the elements.
-(int)check:(int)second {
int maxValue = [[self.arrayOfAllarms lastObject] intValue];
if(maxValue == second){
self.index = 0;
return 2;
} else {
if ([[self.arrayOfAllarms objectAtIndex:self.index] intValue] == second) {
self.index++;
return 1;
} else {
return 0;
}
}
}
Check methods instead is very elementary and I don't think needs explanations.
So, why this simple very stupid app leaks?
Since you're doing this on the main run loop, you can (and should) simplify the ClockRun method:
- (void)ClockRun {
self.time = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(check) userInfo:nil repeats:YES];
}
That NSInvocation code was unnecessary and the NSRunLoop code could only introduce problems.
Having said that, this is unlikely to be the source of your memory consumption. And nothing else in the provided code snippets looks like an obvious memory problem. If you're 100% confident that the timer is getting invalidated, then the timer is not the problem. I wonder about the object graph between the view controller at this mtClockController. Or perhaps some circular reference in view controllers (e.g. pushing from A to B and to A again). It's hard to say on the basis of what's been provided thus far.
Sadly, there's not much else we can suggest other than the routine diagnostics. First, I'd run the the app through the static analyzer (by pressing shift+command+B in Xcode, or choosing "Profile" from the Xcode "Product" menu).
Second, you should run your app through Leaks and Allocations tools to identify the what precisely is leaking on each iteration. Do you have extra instances of the view controllers? Or just the mtClockController?
Until you identify what's not being deallocated, it's hard to remedy it. And Instruments is the best tool for identifying what's not getting released. In WWDC 2012 video iOS App Performance: Memory the demonstration sections of the video give pragmatic demonstrations of using Instruments (as well as a wealth of good background info on memory management).
Third, when I've got a situation where I'm not sure if things are getting deallocated when they should, I sometimes include dealloc methods that tell me when the object is deallocated, e.g.:
- (void)dealloc {
NSLog(#"%s", __PRETTY_FUNCTION__);
}
I'd suggest this not only for your key model objects, but your view controller, too. (Sometimes we agonize over our model objects only to realize that it's the view controller, itself, which is be retained by something else.)
Clearly Instruments is a much richer tool, but this can be used to quickly identify failure to deallocate (and show you what's maintaining the strong references).
I ran you app through Instruments, watching your custom objects, and everything is being deallocated properly. Below, I marked generation A, hit the button, let the timer expire, marked generation B, hit the button again, etc. I did that four times, and I then simulated a memory warning, and did one final generation. Everything looks fine (this is a compilation of six screen snapshots in one, showing the total allocations at each of the six generations):
I inspected your Generations, as well as the Allocations themselves, and none of your objects are in there. Everything is getting released fine. The only things there are internal Cocoa objects associated with UIKit and NSString. Cocoa Touch does all sorts of caching of stuff behind the scenes that we have no control over. The reason I did that final "simulator memory warning" was to give Cocoa a chance to purge what it can (and you'll see that despite what Generations reports, the total allocations fell back down a bit).
Bottom line, your code is fine, and there is nothing to worry about here. In the future, don't worry about incidentally stuff showing up in the generations, but rather focus on (a) your classes; and (b) anything sizable. But neither of those apply here.
In fact, if you restrict Instruments to only record information for your classes with the mt prefix (you do this by stopping a recording of Instruments and tap on the "i" button on the Allocations graph and configure the "Recorded Types"), you'll see the sort of graph/generations that you were expecting:
A couple of observations:
Instead of using the invocation form of scheduledTimerWithInterval, try using the selector form directly, in this case it's a lot simpler and clearer to read.
Since you're call runUntilDate directly, I don't think you're getting any autorelease pools created/drained, which would lead to memory leakage, specifically in the check function. Either don't call runUntilDate and allow the normal run loop processing to handle things (the normal preferred mechanism) or wrap check in an #autoreleasepool block.

How to deallocate objects in NSMutableArray with ARC?

My original project was leaking so I searched for the leak. When I found it I created a simple new project.
The project uses ARC and the only code I added is the following.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
int elements = 10000000;
//memory usage 5,2 MB
NSMutableArray *array = [NSMutableArray arrayWithCapacity:elements];
//memory usage 81,7 MB
for (int i = 0; i < elements; i++) {
[array addObject:[NSObject new]];
}
//memory usage 234,3 MB
[array removeAllObjects];
//memory usage 234,3 MB
array = nil;
//memory usage 159,5 MB
}
After calling [array removeAllObjects] all NSObjects in the array should be deallocated and the memory usage should be 81,7 MB again.
What am I doing wrong?
Here
NSMutableArray *array = [NSMutableArray arrayWithCapacity:elements];
you are creating autoreleased object (autorelease pool).
Many programs create temporary objects that are autoreleased. These
objects add to the program’s memory footprint until the end of the
block. In many situations, allowing temporary objects to accumulate
until the end of the current event-loop iteration does not result in
excessive overhead; in some situations, however, you may create a
large number of temporary objects that add substantially to memory
footprint and that you want to dispose of more quickly. In these
latter cases, you can create your own autorelease pool block. At the
end of the block, the temporary objects are released, which typically
results in their deallocation thereby reducing the program’s memory
footprint
Wrap with #autoreleasepool {} method [NSMutableArray arrayWithCapacity:elements]:
NSMutableArray *array;
#autoreleasepool {
array = [NSMutableArray arrayWithCapacity:elements];
// [NSMutableArray arrayWithCapacity:] creates object with retainCount == 1
// and pushes it to autorelease pool
// array = some_object; usually (and in this case also) is transformed by ARC to
// [array release]; [some_object retain]; array = some_object;
// so here array will have retainCount == 2 and 1 reference in autorelease pool
} // here autorelease pool will call `release` for its objects.
// here array will have retainCount == 1
or change it to
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:elements];
You've been bitten by the dreaded autorelease pool. Essentially to make MRC (manual reference counting) manageable by people instead of releasing an object immediately it can be handed to the autorelease pool (an instance of NSAutoreleasePool, it's documentation gives more details) which will retain the object until the pool is later drained. ARC (automatic reference counting) could be designed so the autorelease machinery is not needed, but to maintain compatibility with MRC is remains.
The pool automatically drained at the end of a run loop cycle - i.e. when the application has finished processing an event. However if an application creates a lot of temporary objects and then discards them is some localised part of the program then a using a local autorelease pool can drastically reduce the maximum memory use. It is not that such temporary objects will not be release, just that they will live far longer than needed. A local pool can be create with the #autoreleasepool { ... } construct.
You can see the effect in your example by wrapping the whole of the body of applicationDidFinishLaunching:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
#autoreleasepool
{
...
}
}
and stepping through with the debugger.
In your real code you need to work back from the point which is producing lots of temporary objects to locate a suitable point to add an autorelease pool.
HTH.
Addendum
It is not the objects in your array that are not getting released when you think they should , you can test this by using a simple class which counts initialisations and deallocations, e.g.:
#interface TestObject : NSObject
+ (void) showCounts;
#end
#implementation TestObject
static uint64_t initCount = 0, deallocCount = 0;
- (id) init
{
self = [super init];
if(self) initCount++;
return self;
}
- (void) dealloc
{
deallocCount++;
}
+ (void) showCounts
{
NSLog(#"init: %llu | dealloc: %llu", initCount, deallocCount);
initCount = deallocCount = 0;
}
#end
Use this instead of NSObject and call showCounts after you are done with your test - try with/without autorelease, etc.
Your memory is always getting released, it is just the time at which it is release that is the issue. Some objects end up in an autorelease pool, either the default one which is emptied once per event, or a local one.
Unless you create a lot of temporary objects in response to a single event you normally won't see an issue. Consider whether you are chasing a real issue for your application here. If you are among the things to try to alleviate the problem are:
Avoid uses of convenience constructors of the form <name>WithX... which are shorthands for [[[C alloc] initWithX...] autorelease]. On many, but not all, occasions the compiler can remove such objects from the autorelease pool just after the convenience constructor returns (and your case appears to be one in which is can fail). The better route is to use alloc/init, new (shorthand for alloc/init) or, if provided, newWithX... (shorthand for alloc/initWithX...). Try these options with your example and see the differences in when (not if) the memory is released.
Well placed #autoreleasepool blocks.
HTH

How to force release on iOS

I'm new to ARC but understand how it works and I'm trying it out. I'm on iOS so memory is a severe concern.
I have a MyObject class which contains lots of big data. I want to release it, and load a new set of data.
MyObject *object;
object = [[MyObject alloc] initWithData:folder1]; // load data from folder1
// later...
object = [[MyObject alloc] initWithData:folder2]; // load data from folder2
This works fine without leaks, and I'm guessing the ARC inserts a [object release] before the new assignment. My problem is the data inside 'object' is released after the new set is allocated, and I run out of memory. What I really want to be able to do is:
object = nil;
<function to pop the pool, wait till everything is deallocated>
object = [MyObject alloc] initWithData:folder2]; // load data from folder2
but I'm not sure how to do that. I could run the new allocation on a performselector afterdelay, but it feels like I'm shooting in the dark and a bit of hack. There's probably a proper way to do this?
P.S I've tried searching for an answer, but all results are about memory leaks and how to make sure variables go out of scope and set variables to nil etc. My issue isn't about that, it's more of a timing thing.
UPDATE
Thanks for the answers, I'd already tried
object = nil;
object = [MyObject alloc] initWithData:folder2];
and it hadn't worked. I wasn't sure whether it was supposed to or not. Now I understand that it is supposed to work, but I must have something else holding on to it for that fraction of a second. I have NSLogs in all of my init/dealloc methods, and I can see first all the inits of the new instances of classes (of MyObject's ivars) being called, and then almost immediately after (within a few ms), the dealloc of MyObject, followed by the deallocs of its ivars.
I also tried the #autorelease but the same thing happens.
I've searched throughout the project and pasted all the code which I think may be relevant to this.
#interface AppDelegate : UIResponder <UIApplicationDelegate>;
#property PBSoundSession *soundSession;
#end
//--------------------------------------------------------------
#implementation AppDelegate
// onTimer fired at 60Hz
-(void)onTimer:(NSTimer *) theTimer {
[oscReceiver readIncoming]; // check incoming OSC messages
// then do a bunch of stuff with _soundSession;
}
#end
//--------------------------------------------------------------
#implementation OscReceiver
-(void)readIncoming {
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
// parse all incoming messages
if(bLoadNewSoundBank) {
NSString *newFolder = parseNewFolder();
appDelegate.soundSession = nil;
appDelegate.soundSession = [MyObject alloc] initWithData:newFolder];
}
}
#end
//--------------------------------------------------------------
#implementation GuiController
// onTimer fired at 10Hz
-(void)onTimer:(NSTimer *) theTimer {
PBSoundSession *soundSession = appDelegate.soundSession;
// update gui with received values
}
#end
I thought it might be the 'soundSession' local variable in the GuiController::onTimer holding onto the old appDelegate.soundSession for the duration of that method, but to my surprise commenting out all of the GUI code (in fact disabling the timer), made no difference.
Is there a way of finding out at that point who is still holding onto my appDelegate.soundSession? I placed a breakpoint where I set it to nil, but couldn't find any useful information. I tried Instruments in Allocation template, but couldn't find anything useful there either (probably because I don't know where to look).
This is what my allocations track looks like, you can see the memory is all deallocated a bit too late!
.
This might not be an an ARC problem. What you could be seeing is your autorelease pool not draining soon enough—your MyObject is getting released, but the data it loaded is getting held onto by the pool because of some internal -retain/-autorelease pair. Try wrapping your -initWithData: calls in an #autoreleasepool block, like this:
#autoreleasepool {
object = [[MyObject alloc] initWithData:folder1];
// do things
}
// later…
#autoreleasepool {
object = [[MyObject alloc] initWitData:folder2];
// do other things
}
Setting the object to nil immediately before setting it to something else as Gabriele suggests might cause the compiler to insert the appropriate release before the second -alloc/-initWithData:, but it might be smart enough to do that already—if that doesn’t work, it’s most likely the autorelease-pool thing.
There is no delay when draining an #autoreleasepool {...}; the objects in the pool have release invoked immediately. If an object survives that, it is because there is either a strong reference elsewhere or because the object was autoreleased into the next pool out.
If you do:
a = [[Foo alloc] initBigThing];
a = nil;
a = [[Foo alloc] initBigThing];
The first instance of Foo will be released prior to the allocation of the second
With one big caveat; if any of the code paths that a is invoked upon happen to retain/autorelease it, then it'll stick around until the pool is drained. Surrounding it in #autoreleasepool{ ... }; should do the trick.
Note that the compiler will sometimes emit retain/autorelease sequences in non-optimized builds that are eliminated in optimized builds.
A bit more general answer, I found how you can force release an object:
#import <objc/message.h>
// ---
while ([[object valueForKey:#"retainCount"] integerValue] > 1) {
objc_msgSend(object, NSSelectorFromString(#"release"));
}
objc_msgSend(object, NSSelectorFromString(#"release"));
But you shouldn't do this because ARC will probably release the object later and this will cause a crash. This method should be only used in debug!

Resources