Running out of memory from spriteFrameCache.addSpriteFrames

My devices are crashing when too many sprite frames get added via the method below. I’m removing sprites when they’re no longer needed but eventually I still get the crash. Note that I can’t wait until the end of a scene to purge unused assets since the crash happens way before the main scene ends. Is there something I’m missing?

cc.spriteFrameCache.addSpriteFrames(plist, png);

Also, I remove the sprites from the cache with this:

cc.spriteFrameCache.removeSpriteFramesFromFile(plist);

you need to remove texture as well, that is what is taking up the core memory:

This removes the sprite frame naming reference:

SpriteFrameCache::getInstance()->removeSpriteFramesFromFile(...

This removes the actual texture which is the hard hit on memory:

Director::getInstance()->getTextureCache()->removeTextureForKey(...

You can make a custom function that removes both if cocos does not have that

Ok. So removeSpriteFramesFromFile doesn’t remove all the textures referenced in the plist from the sprite cache?

No sir, incase you need the texture, but the SpriteFrame data is no longer needed. They are 2 separate things completely

    std::string texturePath("");
    
    if (dict.find("metadata") != dict.end())
    {
        ValueMap& metadataDict = dict["metadata"].asValueMap();
        // try to read  texture file name from meta data
        texturePath = metadataDict["textureFileName"].asString();
    }
    
    Director::getInstance()->getTextureCache()->removeTextureForKey(FileUtils::getInstance()->fullPathFromRelativeFile(texturePath, plist));

I added the above code into removeSpriteFramesFromFile to remove the texture, you can do something similar if you want it to always do that

1 Like

Thanks! I’ll give this a try.

One last question. I see the _textures count going up and down so I’m pretty sure your solution is working to remove the items from the texture cache as expected. However at times I still get the “Terminated due to memory issues” crash. I’m pretty sure it’s related to the spriteframe/texture cache but I’m only loading about 5-10 images (about 2000x4000 pixels each) for animation purposes. Are there some other optimizations you can think of?

2000x4000 x 4 bytes per pixel (assuming you’re using RGBA8888) would be ~32MB per image, so:

5 x 32MB = 160MB
10 x 32MB = 320MB

That’s quite a lot of RAM usage, and that’s assuming you’re always dumping unused textures from memory when you’re finished with them.

2000x4000 is quite a large texture (some devices may not even support it, since the max can be 2048 x 2048). If you are using RGBA8888, consider dropping it to RGBA4444, or even better, optimizing whatever is in those textures. If you have frame based animations, perhaps you can cut down the number of frames per second, which will reduce the number of frames you need to have in the textures.

1 Like

I see what you’re saying but the images aren’t anywhere near that large. There are some that are a few MB (like between 2-5) but most are less than 1MB. Having said that, I can’t say for sure that the size of the images aren’t the problem.

@dragon_fly_jones are you talking about the file size? a 2MB file is not 2MB in raw memory. It is, as @R101 mentioned depending on your render format

Files use compression algorithms. Raw pixel memory is needed for actual rendering.

1 Like

Are you tracking memory with any tool? I use Xcode mainly for C++ and cocos development, so I can watch RAM in real time. If not, you can probably use some std libs and log your memory usage before and after loading/unloading textures and make sure things are working as intended

Here is a good example:

2 files with the same texture size:

testWhite

854 bytes (all white)

testNoise

more than 84,000 bytes (noise).

Your raw memory would use the same amount of memory for both in a render sense, which would be greater than both files sizes as they were compressed for easy transfer.

2 Likes

Aha, you’re a genius. Yes, I’m talking about actual file size. I didn’t realize the footprint could be drastically different in memory.

I usually use Instruments but I typically only pull that out once I’m closer to a stable product.

1 Like

Now you get to be creative on how to minimize memory. For example on the white texture example above, you don’t even need to use a Sprite with a texture as you can use a primitive draw node or LayerColor.