"Not only does this new technique perform better, but by using this method to reference images, the OS has the option of purging image data from memory and reconstituting it directly from the file on an as-needed basis."
Luckily, that's an option it never takes.
"(Whether or not a given version of iOS does this is another story, but at least this technique gives the OS that option.)"
Does any version of iOS that has ever shipped do this? It sounds like wishful thinking. You're just hoping Apple will skate iOS to your puck.
It seems like a terrible idea, given how the rest of the memory management works. How does the OS determine that you actually need the image? And what if, at that moment, it can't be reloaded because the app is out of memory, the file was deleted, what if the file was overwritten, etc?
I'd guess that imageWithContentsOfFile: itself calls dataWithContentsOfFile: rather than something secret or magical, so I'm curious about how much of an actual optimization there is.
It really doesn't seem like a terrible idea at all to me; why NOT use demand paging-style memory management for immutable images like UIImages? This is one of the things that virtual memory is good for.
Apple seems to agree. From the documentation for UIImage in the iOS Reference Library (which as far as I can tell is a public page and not under NDA):
"In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file. This extra load step, however, may incur a small performance penalty."
A moment with IDA shows that it calls CGImageSourceCreateWithFile, which calls mmap, which supports exactly that kind of paging. However, dataWithContentsOfFile: also calls mmap under certain circumstances, so paging should theoretically be possible with either selector.
Yes, it does take advantage. As of OS version 3, if an image is not retained by anything other than the UIImage named image cache and the app receives a low memory warning, the in-memory image is destroyed.
> In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file.
That's actually separate. That's talking about a UIImage purging data, but in this case, it's the entire UIImage that is discarded from the cache that holds UIImages indexed by name.
Oh ok, I had missed that part. So the purging can happen at both level, within the UIImage (which discards its data when it's linked to a file) and within a cache holding a UIImage (which discards the UIImage itself)? (the former seemed to match the described case exactly, which is probably why I missed the difference, sorry)
Emphatic agreement about NSDateFormatter. Be careful about instantiating too many of those.
I wrote an import class to map some JSON to Core Data entities, including a boatload of dates. NSDateFormatter instances were being created during several loops, at a cost of about 800ms, according to Time Profiler.
Refactored the code to use a single instance, shared across every object and method that needed to do date parsing or other date chores. Shaved that 800ms down to about 90.
Check your Cocoa codebase for NSDateFormatter abuse – really easy win.
Another win: Have your server vend binary Plist files instead of JSON or XML. Zero parsing needed, similar file sizes. Cut import times as much as 50%!
12 comments
[ 3.2 ms ] story [ 38.1 ms ] threadLuckily, that's an option it never takes.
"(Whether or not a given version of iOS does this is another story, but at least this technique gives the OS that option.)"
Does any version of iOS that has ever shipped do this? It sounds like wishful thinking. You're just hoping Apple will skate iOS to your puck.
It seems like a terrible idea, given how the rest of the memory management works. How does the OS determine that you actually need the image? And what if, at that moment, it can't be reloaded because the app is out of memory, the file was deleted, what if the file was overwritten, etc?
I'd guess that imageWithContentsOfFile: itself calls dataWithContentsOfFile: rather than something secret or magical, so I'm curious about how much of an actual optimization there is.
Apple seems to agree. From the documentation for UIImage in the iOS Reference Library (which as far as I can tell is a public page and not under NDA):
"In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file. This extra load step, however, may incur a small performance penalty."
http://bethblog.com/index.php/2010/10/29/john-carmack-discus... (Under "Technical Geek Details")
-Ken (Cocoa Frameworks)
http://developer.apple.com/library/ios/#documentation/uikit/...
> In low-memory situations, image data may be purged from a UIImage object to free up memory on the system. This purging behavior affects only the image data stored internally by the UIImage object and not the object itself. When you attempt to draw an image whose data has been purged, the image object automatically reloads the data from its original file.
I wrote an import class to map some JSON to Core Data entities, including a boatload of dates. NSDateFormatter instances were being created during several loops, at a cost of about 800ms, according to Time Profiler.
Refactored the code to use a single instance, shared across every object and method that needed to do date parsing or other date chores. Shaved that 800ms down to about 90.
Check your Cocoa codebase for NSDateFormatter abuse – really easy win.
Another win: Have your server vend binary Plist files instead of JSON or XML. Zero parsing needed, similar file sizes. Cut import times as much as 50%!