Dealing with infinite loops in Objective C - objective-c

I've recently joined an iPad project. In looking through the code base I've come across some unusual things, one of which is this (I've meta-coded this):
while (something.isAlwaysTrue) {
// Wait for something to happen. i.e. Get data from an internet connection.
// Respond to something.
}
I didn't notice any problems with this until I started memory profiling the app and found that these loops are memory leaking massively. The reason being that because they never end, any autorelease instances created inside them are never freed because the method never ends and the autorelease pools never get a chance to free up.
After talking it through with the developers who wrote the code I came up with the following technique:
-(void) queueTask {
// Using GCD or perform with delay, call the process method.
}
-(void) process {
// Wait and/or do stuff.
[self queueTask];
}
The basic idea is that by using a method to queuing through GCD or the runloop, it gives the autorelease pool a chance to execute and clean up autorelease instances. This appears to work just fine.
My question is - is this the best way to go about dealing with these loops? or is there a better way to do it?

Two points;
Minimizing Heap Growth
anyway, here's how minimize memory growth:
while (something.isAlwaysTrue) {
NSAutoreleasePool * pool = [NSAutoreleasePool new];
// Wait for something to happen. i.e. Get data from an internet connection.
// Respond to something.
[pool release], pool = 0;
}
or if you prefer the bleating (sic) edge:
while (something.isAlwaysTrue) {
#autoreleasepool{
// Wait for something to happen. i.e. Get data from an internet connection.
// Respond to something.
}
}
autorelease pools just operate like thread local stacks. when you push a pool, autoreleased objects are added to the top pool in the current thread. when you pop the pool, the pool sends a release message for each autorelease.
using GCD as a substitute for an autorelease pool is odd; similar to using an NSArray of single character NSStrings where you should simply use a single NSString.
Mutithreaded Program Flow
the infinite loop is a very suspicious program. it suggest you may be trying to reinvent run loops. the main run loop is of course common. a secondary thread 1) with a run loop 2) that never ends is unusual.
you should reconsider how the program flows. typically, you act on events, rather than holding your breath, polling until they complete. you may be trying to break from that situation in the program you proposed -- but i don't have enough detail.

Related

Usage of autorelease pool in objectAtindex swizzling for NSMutableArray

- (nullable id)myObjectAtIndex:(NSUInteger)index{
#autoreleasepool {
id value = nil;
if (index < self.count)
{
value = [self myObjectAtIndex:index];
}
return value;
}
}
I have no idea about the purpose of using autoreleasepool here. Can someone give me a hand?
Unless I'm missing the obvious, which is always possible, we can only guess:
There is a stack of autorelease pools, the top of the stack being the one in use. When the #autoreleasepool { ... } construct is entered a new pool is created and pushed on the stack, on exit from the construct the pool is drained and popped off the stack.
The reason to create local pools is given in the NSAutoReleasePool docs (emphasis added):
The Application Kit creates an autorelease pool on the main thread at the beginning of every cycle of the event loop, and drains it at the end, thereby releasing any autoreleased objects generated while processing an event. If you use the Application Kit, you therefore typically don’t have to create your own pools. If your application creates a lot of temporary autoreleased objects within the event loop, however, it may be beneficial to create “local” autorelease pools to help to minimize the peak memory footprint.
So what is the purpose in the code you are looking at? Some guesses:
Either the original author knows/believes that the called methods count and objectAtIndex (post the swizzle) add a significant amount of objects to the autorelease pool and wishes to clean these up; or
The original author was/is planning to add future code to myObjectAtIndex which will add a significant amount of objects to the autorelease pool and wishes to clean these up; or
Wishes to be able to call objectAtIndex and ensure there is no impact on the memory used for live objects (e.g. maybe they were measuring memory use by something else); or
Who knows, accept the original author (hopefully!)
HTH
There is no scientific reason.
The whole code is an example of "this app crashes and I do not know why" panic code:
Obviously the author had a problem with guaranteeing correct indexes, what would be the correct approach. Therefore he wrote a special method to "repair" it. The naming ("my") shows, that he thought: I can do it better (instead of insuring correct indexes).
Moreover, adding an ARP to a piece of code, that obviously does not create an bigger amount of objects, is a sure sign for the fact, that he couldn't oversee his code anymore.
Move the whole code to /dev/null.

Objective c: Bad access error when using performSelectorOnMainThread

Here is the problem.
I have a method called -(void)searchingInBackground which is running in background (performSelectorInBackground).
In this method, I have couple of different threads which are running in background too (performSelectorInBackground). Like this:
-(void)searchingInBackground
{
#autoreleasepool {
[self performSelectorInBackground:#selector(getDuplicatedPictures:) withObject:copyArray];
}
#autoreleasepool {
[self performSelectorInBackground:#selector(getLocationsOfPhotos:) withObject:copyArray];
}
... (and so on)
}
In each of functions in threads (ie. getDuplicatedPictures, getLocationsOfPhotos...) they will generate NSStrings at the end and I will use those strings to update my text field GUI.
In order to update my text field GUI. I created a function called UpdateGUI which will use to help me update all of my NSStrings. Like this,
-(void)UpdateUI
{
[_NumDupPhotosLabel(label for GUI) setStringValue: resultDupPhotos(string from thread function which is getDuplicatedPictures in this case)];
....(includes all of my strings from threads)
}
Here is the problem, when I call this UpdateGUI using performSelectorOnMainThread in each of threads function. It will give me EXC_BAD_ACCESS. Here is what I did.
For example:
-(void)getDupicatedPictures
{
resultDupPhotos = .....;
[self performSelectorOnMainThread:#selector(UpdateUI) withObject:nil waitUntilDone:YES];
}
If I do not use performSelectorOnMainThread, just set the values directly in those functions it works fine. I just want to better organize the code.
-(void)getDuplicatedPictures
{
resultDupPhotos = .....;
[_NumDupPhotosLabel setStringValue: resultDupPhotos]; (works good and it will set the value to the GUI label)
}
Could you guys tell me how to fix this? Thanks!!!
ARC or no?
if you have a crash, post the backtrace
surrounding a performInBackground:... call with an #autoreleasepool does nothing (NSAutoreleasePool isn't going to help, either -- you need the autorelease pool to be in the thread of execution)
if a variable is involved in a crash, show the variable's declaration and initialization
spawning a bunch of threads simultaneously to do a bunch of work is likely to be slower than doing the work sequentially. Concurrency should always be controlled. If you have a long running task, you might likely want to spin up a second thread. Or you might want to re-order operations. The issue, though, is that running multiple threads at once, especially if those threads are doing a lot of I/O, is just going to increase contention and may likely make things slower, often a lot slower.
More likely than not, one of the objects calculated on a background thread is being released before the main thread tries to use it. How do you ensure that resultDupPhotos is valid between threads?

Memory considerations for BFS in Objective-C

I've written a puzzle solver in Objective-C. It uses a breadth first search to explore the states reachable from the initial puzzle state. The search is terminated when the first winning state is encountered. The only optimization is a look-up table that helps prevent re-exploring from a state already seen.
The algorithm seems to work correctly. However profiling shows it's using a lot of memory and I'd like to understand why. I think my gap in understanding is related to the Objective-C run loop and the autorelease pool.
Does the following (simplified) code ever allow the run loop to complete an iteration and drain the autorelease pool?
- (void) search {
while (![myQueue empty]) {
State *state = [myQueue pop];
for (State *s in [state allReachableStates]) {
[myQueue push:s];
}
}
}
Profiling shows lots of memory used for NSArrays. This makes sense as allReachableStates does create a fair number of arrays. Since they're all autoreleased it seems possible that the above code is preventing the autorelease pool from draining.
Note all code is run on the main thread and I'm not using ARC.
Edit: So the fix was wrapping the for loop in an #autoreleasepool.
You're right that the autorelease pool associated with this turn of the runloop won't be drained within this method. It won't be drained until some time after this method returns.
You can wrap the while block in an #autoreleasepool yourself (one for each state)
It's better not to use a lot of autorelease in a for loop. You can check this Understanding Objective-C autorelease memory management

can do anything during a callback ? a basic objective c issue

Sorry for the many posts here regarding this issue but i am having a progress here.
I have a callback function, which is in C , and been called when a new buffer is arrived.
I was told here to not do ANYTHING in that callback ,not malloc , or anything .
Now i want to send my new buffer to another class( which will create a circle buffer and save many buffers).
BUT, the basic thing that i dont get, is that if i call another function from the callback - its the same as doing it in there- becuase in that function i do the DSP and it takes time, so its the same as doing it in that callback- because its in serial.
froof :
i am sending the data to another function in another class, and its ok, but if i try to NSLOG it in there, i AGAIN have this memory leaks.
here is the other class that i call from the callback :
- (id)init
{
self = [super init];
if (self)
{
data = malloc (sizeof(SInt16) * 4000);
}
return self;
}
-(void)sendNewBuffer:(SInt16*)buffer
{
data=buffer;
NSLog(#"data arrived size is : %lu",sizeof(data));
for(int i=0; i<sizeof(data);i++)
{
NSLog(#"%d",data[i]);
}
}
ONLY when comment the log, it works without memory leaks.
that means the callback is waiting for that !
How would i process that data somwhere else in parallel ?
i am spending a week for that now.
thanks.
One possibility for the memory leak when using Objective-C objects such as the NSString in the NSLog is that those objects may be autoreleased (or may internally used autoreleased objects).
Your callback may be called from a different thread. You can confirm this by putting a breakpoint in the callback and looking in the debugger if this is the main thread or a secondary thread.
Any secondary thread must have its own AutoRelease pool. The system creates one automatically for the main thread, but you must create one explicitly if you are to create a secondary thread.
Also, one reason for not allocating stuff in a callback is usually for performances. Often the callback needs to be kept at minimum to avoid blocking the thread that called it.
I would suggest you read a C tutorial. There are at least two problems with your code which we can't really help you with:
data=buffer;: this leaks the previous value of data. You need to copy it to data (memcpy) or release the memory first (free) and then keep the pointer... unless the buffer goes out of scope after the callback, in which case your only option is to copy
sizeof(data): this can't work. data is a pointer; it doesn't know the amount of data that it being pointed at
The second means that you can't correctly implement the call back, at least not without further information. (Either the buffer has some indication of the volume of data or it's a constant size.)
If I had to guess (and I suppose I do) the callback is probably called in an interrupt context, hence malloc etc. would possibly be fatal.
What I would do is copy (ie. memcpy) the data to a buffer, and schedule/signal handling code to run later (eg. using condition variables, a runloop source, etc.)

Why is this Objective-C code allocating GBs of RAM, releasing it later, and not reporting any leaks?

I have inherited some code, and it looks like this:
- (bool)makeOneLevel:(int)nummines objects:(int)numobjects
{
[field release];
state = gameWait;
field = [[MineField alloc] createLevel:nummines objects:numobjects];
if([field rating] == -1)
{
return false;
}
...
There is always one MineField allocated. Whenever you make a new field, the first thing the function does is release the old one. If the function succeeds in making a MineField, then it returns true.
I also have this:
while(numsaved < self.makeNumber)
{
while(![mineView makeOneLevel:self.makeNumMines objects:self.makeNumObjects])
{
}
{
//saving code here
}
numsaved++;
}
Which calls the function until it creates a valid MineField. This all works. But it allocates GBs of RAM while doing it. But the Leaks tool finds no leaks, and when the outer while finishes and the OS gets control back, all that RAM is deallocated just fine.
Am I doing something wrong with the MineField allocation, or should I be looking elsewhere in the creation process?
Without knowing the internals it's impossible to say for sure, but the behavior you're describing sounds like -[MineView makeOneLevel:objects:] is internally allocating and autoreleasing objects. Since the AppKit default event loop creates and cleans up an autorelease pool for each event it processes, everything does end up going away eventually, but not until the event is finished processing (e.g, after your method exits).
The easiest solution will be to wrap your own autorelease pool around the while() loop, and drain it either every time around the loop or periodically. If you aren't too scared of the internals of the method you're calling in the loop, though, you may be better off just finding where it's autoreleasing objects and fix it (by making it explicitly release objects when appropriate).
If you do not get any better answers, try using the heap profiler from Google perftools to track down where the huge allocations are happening.