Using CALayer memory for hidden drawing cache?

I am having a problem with CoreGraphics / CoreAnimation on iPhone. To better explain how the problem manifests, I will walk you through my current setup and illustrate the code where necessary.

I am trying to draw a bunch of preloaded images in a UIView CALayer , but whenever the image is displayed, the memory consumption of the application increases and the memory is not restored whenever the image changes.

Images are UIImage by reading them through UIImage objects, rendering them into a Bitmap context, and extracting CGImageRef from this context. The purpose of this is to unzip and scale the images so that these operations are not performed at every draw. A similar recommendation can be found in Apple Q & A on this subject (search for CGContextDrawImage performance, if you're interested). The context is set to 8 bits per component and pre-multiplied alpha.

After the images are unpacked into a raster image, they are saved in NSArray and later assigned (not saved) to the user-defined subclass of UIView that executes the drawing. I tried various approaches to drawing images, and by far the fastest method directly sets the view CALayer contents property. Other methods, such as drawLayer:inContext: and drawRect: have different effects on frame rates, but they all have the same memory behavior.

The problem is that after changing the contents property, I see a surge in the memory in the tools and this memory does not fall even after the image is no longer displayed. Object selections remain constant, so I assume that CoreAnimation creates some implicit cache to speed up drawing. However, as I said, this cache is not released when necessary, and a gradual build-up leads to failure in just a couple of minutes of work.

The contents property saves the object, and I do not explicitly release it, because I want the original images to remain in memory for the duration of the application; Also, a high retention rate would not account for the bursts of memory that I see.

When I look at the stack, I see that CoreAnimation makes calls to functions like CA::Render::copy_image , which makes me believe that it duplicates the contents of the layer somewhere out of reach. I believe that there is a good reason for this, but I don’t know how and when to clear this show stop error at present.

So can anyone with confusing CA knowledge please explain to me if I am doing something wrong and how I can get around this behavior.

Thanks.

+4
source share
3 answers

@ CouchDeveloper - thanks for taking the time to respond.

I did a little work and I will answer my question, instead of answering directly, perhaps the understanding I received will help others who have similar problems.

Your opinion about the allocation and use of memory is correct. The memory I'm looking at is the "real" (resident) memory used by the application in the Monitor Monitor (Activity Monitor) tool.

I think I discovered the reason for these mysterious memory allocations. When CoreAnimation encounters an image that is not in its own pixel format, it copies the image to its own buffer, and it seems to be the usage that I see. I believe that the correct format is 32 bits, host byte order, pre-multiplied alpha first (bitmap information kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host ).

To find out which instances of CGImageRef are being copied and study the internal workings of the framework in more detail, you can use the Core Animation tool on the device or specify several environment variables and run iPhone Simulator from the line command. A list of all flags can be found here . In my case, the most useful combination is CA_COLOR_COPY and CA_LOG_IMAGE_COPIES , which will give the copied images blue overlays and copies of the logs to stderr.

I still have some weird problems ("no data pointer", not pre-multiplexed alpha, etc.), but I think this is mainly due to the way I create or skip images around, but I think that I am on an accelerated solution to all memory problems.

Hope this can be useful for others wondering where their memory and performance problems come from!

+5
source

I am doing exactly what you described - without studying the leaks. Perhaps this will help when you provide your source.

However, I believe that CA allocates system memory that are not recorded in the "Object Selection Tools" in the "Activity Monitor" Tools, respectively, in the "Memory Monitor", namely, "Physical memory is free." "Physical Memory Free" decreases when an image is drawn in an off-screen context, and it also decreases when this image is displayed.

The memory will not be freed (including the one used for display) until the image is freed (although it would be nice to know how this memory can be freed explicitly).

In your case, if you have an UIImages array as a cache, the system memory used for these images should be freed when the array of images is freed and there are no further references to UIImage objects.

If you did not provide your source, I would suggest that your bill for saving your CGImageRefs is not balanced - and therefore they leak. Please note that CGImageRef should not be directly placed in NSArray - they do not behave like Objective-C objects (as well as a free bridge for UIImage) - you need to explicitly call CGImageRetain / CGImageRelease.

+2
source

Have you found a solution to your problem? I have exactly the same problem. I use 32-bit PNG files, I thought that would be enough. I really made sure not to use ImageNamed, since this one is famous for caching things.

I used imageWithData and even made sure that NSData initWithContentsOfFile has the Nocache NSRead option to prevent FS caching, but that didn't change anything.

UPDATE: I found what was my question. didn’t delete the view from his supervisor (which was not displayed), and it seems that some cache was saved somewhere ...

+1
source

All Articles