Our app creates alot of small objects while running. It mostly comes down to Autoreleased NSString and NSNumber objects. Since the app is designed to run "24/7" in the background heap fragmentation becomes a big issues.
What are the techniques to avoid that without a complete restructure of the program.
I was thinking: - object pools that would return the object to a pool after the final release, but objets need to be mutable then. (will NSMuttableString cause heap fragmentation by itself?)
How are others dealing with this issues?
EDIT: This is how I've got suspicious to memory fragmentation. Look at rpages and [vm-pageshortage]
eIncident Identifier: 81E87769-8E16-4439-AFFA-6D077E01E5ED
CrashReporter Key: 96235931c31c6b92a16f5c1b1e4cb363a3d18a67
Hardware Model: iPhone4,1
OS Version: iPhone OS 7.0.4 (11B554a)
Kernel Version: Darwin Kernel Version 14.0.0: Fri Sep 27 23:00:48 PDT 2013; root:xnu-2423.3.12~1/RELEASE_ARM_S5L8940X
Date: 2013-12-13 22:43:36 -0800
Time since snapshot: 1582 ms
Free pages: 1105
Active pages: 3668
Inactive pages: 2035
Speculative pages: 46
Throttled pages: 100120
Purgeable pages: 0
Wired pages: 22159
File-backed pages: 5400
Anonymous pages: 349
Compressions: 0
Decompressions: 0
Compressor Size: 0
Uncompressed Pages in Compressor: 0
Largest process: Argus
Processes
Name <UUID> rpages recent_max fds [reason] (state)
Facebook <979b9707d85a31df94b986d91d8c3ce7> 2368 2368 100 [vm-pageshortage] (resume)
MobileSMS <339505ebbbc4301e87379b095a38ba13> 1448 1448 100 [vm-pageshortage] (background)
MobileMail <b3574f4bded1315cb2e50e5de205be48> 1575 1575 100 [vm-pageshortage] (resume) (continuous)
tccd <1fea8c5a71943151b5cd304c7eb0fd8c> 198 198 100 [vm-pageshortage] (daemon)
kbd <be2d64e41bf43e48a09a23fb129eb0b4> 739 739 100 [vm-pageshortage] (daemon)
librariand <15fb21b24e823e158caed9f9e9d8b87a> 299 299 100 [vm-pageshortage] (daemon)
MobilePhone <10e2242652423ae28f278a807a0d6384> 1852 1852 200 [vm-pageshortage] (continuous)
CVMServer <f26614f7fef63e2faa518272f0fc600a> 96 96 200 [vm-pageshortage] (daemon)
Argus <d214b453a3453121a8495d5c8eba80fd> 51299 51299 100 [vm-pageshortage] (location) (frontmost) (resume)
identityservices <18cc20db2e4739a782cc8e38e03eff52> 398 398 100 (daemon)
wifid <a5cf99e5a0f032a69bc2f65050b44291> 652 652 25 (daemon)
syslogd <6539f4cf4dcf34daadf1d99991926680> 140 140 50 (daemon)
powerd <0a253ac2a99236809422214be1700bc0> 126 126 100 (daemon)
vmd <93cffd22b64631afa08a42f6a85e1f33> 297 297 100 (daemon)
imagent <bef102e1faef39209926fb25f428a71e> 438 438 100 (daemon)
One way to deal with this issue is to find the "90%" culprit that is causing fragmentation issue. You likely have a pathological condition in your code that causes the swiss-cheese effect.
Preliminary Actions
It goes without saying thatyou should first convince yourself that your high page usage is due to fragmentation and not due to a memory leak. :-)If you haven't done so already, using the "Instruments" app in Xcode is an excellent way to watch your program allocate memory in the iOS simulator. Using the Allocations and Leaks tools lets you record every object allocation and malloc() your code does, along with handy timestamps. (And for free, the Leaks tool it will show you cycles in your object map if ARC isn't freeing memory like it should.)
Normally the tools keep track of memory that is still being used. You can select the Created & Destroyed option in the Allocations configuration pane to keep track of everything, which is viewable in pop-up right above the summary information.
There is also a VM page allocation tool that might shed some light on your issue.
Possible Remedies
Once you have determined the culprit, you can restructure your code to prevent the pathological condition. Or if restructuring is too expensive, you can mitigate the effects of the condition by reusing the memory.
Typically when the analysis shows that object allocation and deallocation is causing holes or a particular object is being allocated/deallocated at an alarming frequency, I take the offending culprit and make it into an object "pool".
This can be as simple as storing objects in an NSMutableArray and pushing and popping them as needed.
Of course you might want something a little more sophisticated that initializes objects when fetched, primes the pool with ready objects, and auto-refills with objects when it is empty or runs low. In iOS you'd also want to prune the pool if too many objects collect, or a low memory warning is received.
The nice thing is that this can be very generic code that you can reuse forever. :-)
Side Note
You mention the issue of not wanting to make objects Mutable. In some cases (like NSString) it can help with efficiency if you know (in advance) the space requirements and manipulations you'll need to perform on the string. That way you can tell it in advance how much space you'll need and operate on the string "in-place", reducing allocation overhead. (What NSString does under-the-hood is a whole other article. :-)