How to avoid heap fragmentation in iOS

3.9k views Asked by At

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)
1

There are 1 answers

0
Jim Hayes On BEST ANSWER

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 that you 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. :-)