VM Tracker shows big dirty size

There is a part in my application where I perform operations at the same time. They consist of initializing many CALayers and rendering them into bitmaps.

Unfortunately, during these operations (each takes about 2 seconds to complete on iphone 4), the Dirty Size specified by VM Tracker increases to ~ 120 MB. Allocation extends up to ~ 12 MB (does not accumulate). In my opinion, the size of Dirty is memory that cannot be freed. so often, my application and all other applications in the background die.

Incident Identifier: 7E6CBE04-D965-470D-A532-ADBA007F3433 CrashReporter Key: bf1c73769925cbff86345a576ae1e576728e5a11 Hardware Model: iPhone3,1 OS Version: iPhone OS 5.1.1 (9B206) Kernel Version: Darwin Kernel Version 11.0.0: Sun Apr 8 21:51:26 PDT 2012; root:xnu- 1878.11.10~1/RELEASE_ARM_S5L8930X Date: 2013-03-18 19:44:51 +0800 Time since snapshot: 38 ms Free pages: 1209 Active pages: 3216 Inactive pages: 1766 Throttled pages: 106500 Purgeable pages: 0 Wired pages: 16245 Largest process: Deja Dev Processes Name UUID Count resident pages geod <976e1080853233b1856b13cbd81fdcc3> 338 LinkedIn <24325ddfeed33d4fb643030edcb12548> 6666 (jettisoned) Music~iphone <a3a7a86202c93a6ebc65b8e149324218> 935 WhatsApp <a24567991f613aaebf6837379bbf3904> 2509 MobileMail <eed7992f4c1d3050a7fb5d04f1534030> 945 Console <9925a5bd367a7697038ca5a581d6ebdf> 926 (jettisoned) Test Dev <c9b1db19bcf63a71a048031ed3e9a3f8> 81683 (active) MobilePhone <8f3f3e982d9235acbff1e33881b0eb13> 867 debugserver <2408bf4540f63c55b656243d522df7b2> 92 networkd <80ba40030462385085b5b7e47601d48d> 158 notifyd <f6a9aa19d33c3962aad3a77571017958> 234 aosnotifyd <8cf4ef51f0c635dc920be1d4ad81b322> 438 BTServer <31e82dfa7ccd364fb8fcc650f6194790> 275 CommCenterClassi <041d4491826e3c6b911943eddf6aaac9> 722 SpringBoard <c74dc89dec1c3392b3f7ac891869644a> 5062 (active) aggregated <a12fa71e6997362c83e0c23d8b4eb5b7> 383 apsd <e7a29f2034083510b5439c0fb5de7ef1> 530 configd <ee72b01d85c33a24b3548fa40fbe519c> 465 dataaccessd <473ff40f3bfd3f71b5e3b4335b2011ee> 871 fairplayd.N90 <ba38f6bb2c993377a221350ad32a419b> 169 fseventsd <914b28fa8f8a362fabcc47294380c81c> 331 iapd <0a747292a113307abb17216274976be5> 323 imagent <9c3a4f75d1303349a53fc6555ea25cd7> 536 locationd <cf31b0cddd2d3791a2bfcd6033c99045> 1197 mDNSResponder <86ccd4633a6c3c7caf44f51ce4aca96d> 201 mediaremoted <327f00bfc10b3820b4a74b9666b0c758> 257 mediaserverd <f03b746f09293fd39a6079c135e7ed00> 1351 lockdownd <b06de06b9f6939d3afc607b968841ab9> 279 powerd <133b7397f5603cf8bef209d4172d6c39> 173 syslogd <7153b590e0353520a19b74a14654eaaa> 178 wifid <3001cd0a61fe357d95f170247e5458f5> 319 UserEventAgent <dc32e6824fd33bf189b266102751314f> 409 launchd <5fec01c378a030a8bd23062689abb07f> 126 **End** 

On closer inspection, a dirty memory consists mainly of IO images and Core Animation. multiple entries consisting of hundreds or thousands of pages. What does Image IO and Core Animation do? and how to reduce dirty memory?

edit: tried to do this in a sequential queue and did not improve the size of the dirty memory

another question. how big is too big for dirty memory and distribution?

Updated:

 - (void) render { for (id thing in mylist) { @autorelease { CALayer *layer = createLayerFromThing(thing); UIImage *img = [self renderLayer:layer]; [self writeToDisk:img]; } } } 

in createLayerFromThing (thing); I actually create a layer with lots of sublayers

UPDATED

first screenshot for maxConcurrentOperationCount = 4

seconds for maxConcurrentOperationCount = 1

maxConcurrentOperationCount = 4

maxConcurrentOperationCount = 1

==================================================== ==================================================== ==================================================== ======

and since it reduces the number of simultaneous operations, barely made a dent, I decided to try maxConcurrentOperationCount = 10

maxConcurrentOperationCount = 10

+5
source share
3 answers

It's hard to say what is going wrong without any details, but here are a few ideas.

a. Use @autorelease. CALayers generate bitmaps in the backgound, which together can take up a lot of space if they are not freed in time. If you create and render many layers, I suggest adding an autocomplete block to the rendering cycle. This will not help if ALL of your layers are nested and needed at the same time for rendering.

 - (void) render { for (id thing in mylist) { @autorelease { CALayer *layer = createLayerFromThing(thing); [self renderLayer:layer]; } } } 

Q. Also, if you use CGBitmapCreateContext for rendering, do you call the appropriate CGContextRelease? This also applies to CGColorRef.

C. If you allocate memory using malloc or calloc, do you free it when done? One way to ensure that this happens

Put your render loop code to provide more context.

+4
source

I believe that there are two possibilities:

  • Elements that you create are not auto-implemented.
  • The memory you take is what it is, due to the number of simultaneous operations that you perform.

In the first case, the solution is simple. Send an autorelease message to the layers and images when you create them.

In the second case, you can limit the number of simultaneous operations using NSOperationQueue . Operational queues have a property called maxConcurrentOperationCount . I would try with a value of 4 and see how the behavior of the memory changes from what you have. Of course, you may have to try different values ​​to get the right memory and performance balance.

+2
source

Auto-update will wait for the start of the run cycle to clear. If you explicitly release it, it can take it from the heap without populating the pool.

 - (void) render { for (id thing in mylist) { CALayer *layer = createLayerFromThing(thing); // assuming this thing is retained [self renderLayer:layer]; [layer release]; // this layer no longer needed } } 

Also run the assembly with the analysis and see if you have any leaks and fix them too.

0
source

Source: https://habr.com/ru/post/971520/


All Articles