I've got a thread safety bug somewhere in a fairly large set of code. It's reproducible as a random crash simply by scrolling around in my CATiledLayer for a few seconds in the simulator, and solvable by locking my drawing code into a single thread (which is not ideal, since CATiledLayer is designed to be multi-threaded and my drawing code is slow enough to need it).
How do I go about debugging a thread safety issue? I suspect it's somewhere in my code to lazily fetch (and cache) the data which is being drawn, but that doesn't narrow it down much.
I've skim read the Concurrency Programming Guide, but don't see anything that talks about debugging, it just talks about how to structure your code.
Which concurrency method do you use? GCD or NSThread? And if I can't convince you to use single thread for drawing, try to use #syncronized in your setter/getter methods (or atomic properties, if you use synthesized setters/getters).
Related
I just started creating an app using SceneKit and SpriteKit and ARC for the first time. I noticed that the memory usage is quickly increasing when I switch between different Views. My first thought was that I have memory leaks but I am not sure now. The behavior even occurs in this basic example:
for(int r=0;r<9999999;r+=1){
NSString *s=[NSString stringWithFormat:#"test%i",r];
s=nil;
}
From my understanding an NSString Object is created and directly released in this loop. I've tried this example in the iPhone-Simulator and on an iPhone and it makes the app use several hundreds MB of RAM after this loop is executed. (I am checking the memory usage with the Xcode debug navigator)
I am obviously misunderstanding something. Why is this example still retaining memory afterwards?
edit:
You could also create a new project: iOS -> Game -> Game Technology: SceneKit
Then add this into viewDidLoad:
for(int r=0;r<999999;r+=1){
SCNNode *tn=[SCNNode node];
tn=nil;
}
The memory will peak at 550MB and go down to 300MB which would be to much if there objects were fully released and removed from the RAM.
Don't rely on NSString for memory diagnostics. It has fairly atypical behavior.
This is a not-uncommon scenario, one that I've seen on S.O. more than once, that in an attempt to reduce some complicated memory problem to something simpler, the developer creates a simplified example using NSString, unaware that choosing that particular class introduces curious, unrelated behaviors. The new "Debug Memory Graph" tool or the old tried-and-true Instruments (discussed below) is the best way to diagnose the underlying issues in one's code.
As an aside, you talk about releasing objects immediately. If your method doesn't start with alloc, new, copy or mutableCopy, the object returned will not deallocated immediately after falling out of scope, because they're autorelease objects. They're not released until the autorelease pool is drained (e.g., you yield back to the run loop).
So, if your app's "high water" mark is too high, but memory eventually falls back to acceptable levels, then consider the choice of autorelease objects (and/or the introducing of your own autorelease pools). But generally this autorelease vs non-autorelease object distinction is somewhat academic unless you have a very long running loop in which you're allocating many objects prior to yielding back to the run loop.
In short, autorelease objects don't affect whether objects are deallocated or not, but merely when they are deallocated. I only mention this in response to the large for loop and the contention that objects should be deallocated immediately. The precise timing of the deallocation is impacted by the presence of autorelease objects.
Regarding your rapid memory increase in your app, it's likely to be completely unrelated to your example here. The way to diagnose this is to use Instruments (as described in WWDC 2013 Fixing Memory Issues). In short, choose "Product" - "Profile" and choose the "Leaks" tool (which will grab the essential "Allocations" tool, as well), exercise the app, and then look at precisely what was allocated and not released.
Also, Xcode 8's "Debug Object Graph" tool is incredibly useful, too, and is even easier to use. It is described in WWDC 2016's Visual Debugging with Xcode. With this tool you can see a list of objects in the left panel, and when you choose one, you can see the object graph associated with that object, so you can diagnose what unresolved references you might still have:
By the way, you might try simulating a memory warning. Cocoa objects do all sorts of caching, some of which is purged when there's memory pressure.
If you turned on any memory debugging options (e.g., zombies) on your scheme, be aware that those cause additional memory growth as it captures the associated debugging information. You might want to turn off any debugging options before analyzing leaked, abandoned or cached memory.
Bottom line, if you're seeing growth of a couple of kb per iteration and none of the objects that you instantiate are showing up and you don't have any debugging options turned on, then you might not need to worry about it. Many Cocoa objects are doing sundry cacheing that is outside of our control and it's usually negligible. But if memory is growing by mb or gb every iteration (and don't worry about the first iteration, but only subsequent ones), then that's something you really need to look at carefully.
When I first read about NSZone and what it was, I got really excited about the prospect of using zones to isolate threads' memory spaces such that I could effectively kill a thread and dealloc its zone. But it seems NSZone can't really be used for this purpose after all.
So I'm wondering if there's any way to isolate a thread in Objective-C to a particular block of memory that can be killed and dealloced safely?
Failing that, are there ways to spawn child processes (that surely do have their own memory spaces) in Objective-C, similar to how Chrome does things?
Inter-process communication is a subject that is far too challenging for what you're trying to implement. So long as you're just looking for a representation of some work that you can cancel and deallocate, a subclass of NSThread is perfect. By overriding -main, you can have all the benefits of an NSOperation (not caring exactly which thread work occurs on, abstraction from actual threading, encapsulation, etc.), but in a more concrete and cancelable form.
I'm creating my managed object context with NSPrivateQueueConcurrencyType concurrency type.
Also I'm using performBlock: selector to execute operations in background. So If I'm fetching some objects in background (in performBlock:), is it safe to use resulting managed objects in main thread?
As a general rule, no it is not safe to share NSManagedObject instances across threads no matter what concurrency type you are using.
However there is a library you can use to make your context(s) and object instances thread-safe. With that you can pretty much ignore all the nonsense about ensuring thread isolation between contexts and focus your efforts on the things that matter, like building out the actual functionality of your app.
I'm not 100% sure, but in my own experience I do it this way: If you are changing the variables properties, do it inside performBlock. I had one case where reading was causing some weird behavior, but in general it seems to be OK. If you want to be extra safe, use performBlock every time you touch a managed object in any way.
You will need to use a different context for each thread as explained here iOS Developer - Core data multithreading
One way to implement is described at Core Data - one context per thread implementation
Sorry, I should've search better, here is exactly my question & answer to it:
Core Data's NSPrivateQueueConcurrencyType and sharing objects between threads
I know that Apple officially recommends UIKit to be used in the main thread only. However, I've also heard claims that UIImage is thread-safe since iOS 4.0. I cannot find any documentation backing this claim.
Does anyone have any information to support this claim? As a class used to store data and decode image data, UIImage should be thread-safe if well designed.
Directly from Apple's documentation for UIImage
Image objects are immutable, so you cannot change their properties after creation. This means that you generally specify an image’s properties at initialization time or rely on the image’s metadata to provide the property value. It also means that image objects are themselves safe to use from any thread. The way you change the properties of an existing image object is to use one of the available convenience methods to create a copy of the image but with the custom value you want.
(Emphasis mine)
So at least in the current version of the SDK as of May 13, 2014, "image objects are themselves safe to use from any thread."
It is true that apple recommends using elements from the UIKIt on the main thread:
Note: For the most part, UIKit classes should be used only from an
application’s main thread. This is particularly true for classes
derived from UIResponder or that involve manipulating your
application’s user interface in any way.
Since UIImage isn't derived from UIResponder, and you do not actually display it on the interface/screen. Then doing operations with UIImages on another thread should be safe.
This is however based on my experience, I haven't seen any official documentation about it.
It looks like Apple have updated their documentation since the earlier answers here were posted. According to the most up-to-date documentation, it is safe to create and use UIImage instances from any thread:
Because image objects are immutable, you cannot change their
properties after creation. Most image properties are set automatically
using metadata in the accompanying image file or image data. The
immutable nature of image objects also means that they are safe to
create and use from any thread.
https://developer.apple.com/reference/uikit/uiimage
In the What's New in iOS: iOS 4.0 release notes, the UIKit Framework enhancements include this bit:
Drawing to a graphics context in UIKit is now thread-safe.
Specifically: The routines used to access and manipulate the graphics
context can now correctly handle contexts residing on different
threads. String and image drawing is now thread-safe. Using color and
font objects in multiple threads is now safe to do.
So UIImage is thread-safe on iOS 4.0 and later.
Just to make it short:
UIImage is not thread safe, or better does only work on the main thread,
as I have experienced in my current after some debugging.
I hope that helps.
I wish to have more clarity about this from Apple
or even better an UIImage class, that could be rendered in a different thread.
Shouldn't be too difficult ...
edit:
After some research, I found that it is "UIGraphicsGetImageFromCurrentImageContext();"
that causes the trouble.
it's a bit off the topic, but maybe this helps:
https://coderwall.com/p/9j5dca
Thanks to Zachary Waldowski.
Thread-safe is not the issue, in that any thread can attempt to access a context at the same time (concurrently). And, while that is generally okay, in low-memory situations, like with a Photo Editing Extension on iOS devices, two threads accessing one context can crash an app due to low memory.
This happens when mixing Core Image filters with vImage operations. Both are thread-safe, but ARC will not release vImage buffer data before processing a Core Image object, so you have at some point two copies of an image in memory.
Accordingly, you never consider your knowledge of thread safety to be complete without understanding of threading and concurrency—and that goes double for any answer to questions about thread safety. In short: the proper question is, how does thread-safety apply to memory usage, whenever you're talking about image processing.
If you're just kicking the tires here, you need to wait to pose your question until you've encountered a real problem. But, if you're planning your next move, you need to know how to execute image processing commands sequentially, and with manual deallocation. You must design your app so that there is only one copy of the image being processing in memory. Never rely on automatic deallocation—thread-safe or not—to make that call for you. IT WILL NOT WORK.
Most iPhone code examples use the nonatmoc attribute in their properties. Even those that involve [NSThread detachNewThreadSelector:....]. However, is this really an issue if you are not accessing those properties on the separate thread?
If that is the case, how can you be sure nonatomic properties won't be accessed on this different in the future, at which point you may forget those properties are set as nonatomic. This can create difficult bugs.
Besides setting all properties to atomic, which can be impractical in a large app and may introduce new bugs, what is the best approach in this case?
Please note these these questions are specifically for iOS and not Mac in general.
First,know that atomicity by itself does not insure thread safety for your class, it simply generates accessors that will set and get your properties in a thread safe way. This is a subtle distinction. To create thread safe code, you will very likely need to do much more than simply use atomic accessors.
Second, another key point to know is that your accessors can be called from background or foreground threads safely regardless of atomicity. The key here is that they must never be called from two threads simultaneously. Nor can you call the setter from one thread while simultaneously calling the getter from another, etc. How you prevent that simultaneous access depends on what tools you use.
That said, to answer your question, you can't know for sure that your accessors won't be accessed on another thread in the future. This is why thread safety is hard, and a lot of code isn't thread safe. In general, if youre making a framework or library, yeah, you can try to make your code thread safe for the purposes of "defensive programming", or you can leave it non-thread safe. The atomicity of your properties is only a small part of that. Whichever you choose, though, be sure to document it so users of your library don't have to wonder.