How to avoid heap fragmentation in iOS
Asked Answered
F

1

8

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)
Furl answered 14/12, 2013 at 20:9 Comment(6)
I am just curious: How did you detect/measure the heap fragmentation? What problem did it cause exactly?Traverse
How do you intend to control the internal memory allocations of those classes?Ahwaz
iOS kills out app and bunch of others when the memory is low. We do handle low memory warning and clear out most of the memory down to around 10Mb so that's not the problem.Furl
In iOS7 crash logs for Unknown process started appearing with a list of apps that were killed with a reason [vm-pageshortage]Furl
I think this is a known deficiency in iOS7. Many "24/7" apps seem to be affected. Safari often causes this crash. Our app as well, mostly on 5S. There's not a lot you can do, because (in our case at least) we're well within limits of memory usage. Typically using 200MB on a 1GB device.Michelemichelina
Steven Kramer we have this problem even if using only 11MB ob memory after Memory Warning. Flustrating.Furl
E
4

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

Elevation answered 5/3, 2014 at 5:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.