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?
Related
FACTS:
I have a method executing on a background thread :
[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
This method basically contains a while loop that keeps on executing until the user clicks on a Quit button:
-(void) playOn: (UIViewController*) thisViewController
{
while(!quitButtonPressed)
{
// this is my method's main loop
}
}
PROBLEM:
If the user clicks on Quit somewhere in the middle of the above loop
the rest of the loop would have to execute before it checks the BOOL once again and eventually stops. In order to prevent that from
happening and have the while-loop stop as soon as the user clicks on
Quit, I guess I could also add many if(quitButtonPressed) break;
here and there in my while loop in order to semi-constantly check and "immediately" break away if needed. However, this doesn't seem
very clever or practical from a design perspective given the size of
the above main while-loop and the fact that it contains many smaller
while-loops inside of it (the number of if.. break; I would have to
add would be quite big and could make things quite complicated to
figure out..)
POSSIBLE SOLUTION (but is it the right one?) :
So I was thinking that the best way would be to stop/cancel the
background thread on which the above method's while loop is executing,
instead of the while-loop itself, inside the method, the moment the
user clicks on Quit
Is this, or something similar (i.e. a better suggestion), possible and
how exactly could I do this?
POSSIBLE IMPLEMENTATION OF ABOVE SOLUTION:
I could create this new method:
-(void)checkQuitButton
{
while(!quitButtonPressed)
{
//wait
}
if(quitButtonPressed)
{
// stop this thread-->[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
// this is the method I'm looking for
}
}
And then I could start executing the above and my previous main method concurrently on two separate background threads as follows:
[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
[currentGame performSelectorInBackground:#selector(checkQuitButton) withObject:nil];
While the game while-loop is being executed another while-loop is checking the QuitButton at the same time. But is there a method that I can actually call in order to cancel what was started here:
[currentGame performSelectorInBackground:#selector(playOn:) withObject:self];
?
The correct solution is to periodically check for a "stop" flag. Abruptly terminating a thread provides no opportunity to clean up resources. In short, you would leak memory terribly.
But the deeper issue is that you almost certainly should not have this kind of thread. It strongly suggests an incorrect design. In iOS, most background operations should take the form of focused operations, implemented either with NSOperation or blocks with Grand Central Dispatch. You should very, very seldom need a long lived thread that is performing many different kinds of functions. Within your operation, it should be fairly straightforward where to put the "check for cancel" statements.
There is also almost no case where you should use performSelectorInBackground:. It is an incredibly dangerous method that gives you very little control. Instead, read the Concurrency Programming Guide for guidance on how to properly implement background operations. Pay special attention to the section "Migrating Away From Threads."
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.)
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.
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.
I have been doing some testing with ObjectiveResource (iOS->Rails bridge). Things seem to work, but the library is synchronous (or maybe not, but the mailing list that supports it is a mess).
I'm wondering what the pitfalls are to just running all calls in a performSelectorInBackground... in small tests it seems to work fine, but that's the case with many things that are wrong.
The only caveat I've noticed is that you have to create an Autorelease Pool in the method called by performSelectorInBackground (and then you should only call drain and not release?).
performSelectorInBackground: uses threads behind the scenes, and the big thing with threads is that any piece of code touched by more than one is a minefield for race conditions and other subtle bugs. This obviously means drawing to the screen is off-limits outside the main thread. But there are a lot of other libraries that are also not threadsafe, and any code using those is also tainted.
Basically, thread-safety is something you have to intentionally put in your code or it's probably not there. ObjectiveResource doesn't make any claims to it, so already I would be nervous. Glancing at the source, it looks like it mainly uses the Foundation URL loading machinery, which is threadsafe IIRC. But the ObjectiveResource code itself is not. Just at a glance, all of the class methods use static variables, which means they're all subject to race conditions if you performSelectorInBackground: more than once with code that uses them.
It looks like the 1.1 branch on their Github has explicit support for async through a ConnectionManager class. Probably better off using that (though this is essentially unmaintained code, so caveat emptor).
So are you actually experiencing any issues? Or are you just anticipating them?
Running on a background thread shouldn't give you any issues, unless you try to update a UI element from that same background thread. Be sure to forward any UI-related activities to the main thread. For example (pseudo):
- (void)viewWillAppear:(BOOL)animated {
[self performSelectorInBackground:#selector(refreshTableView)];
[super viewWillAppear:animated];
}
- (void)refreshTableView {
// Where _listOfObjects is used to populate your UITableView
#synchronized(self) {
self._listOfObjects = [MyDataType findAllRemote];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
Note also (as above) that if you are changing the value of any instance variables on the background thread, it's important that you synchronize on self to prevent any other threads (like the main thread) from accessing objects in the _listOfObjects array while it is being updated or set. (Or you may "get" an incomplete object.)
I'm not 100% positive (comments are welcome), but I believe that if you declare the _listOfObjects property as atomic, you won't need to worry about the synchronized block. Though, you would need the synchronized block regardless of the #property declaration if, instead of reassigning the value of the property, you were instead making changes to a single, persistent instance. (Eg. Adding/removing objects from a static NSMutableArray.)