memory questions

Before starting my topic I shall said that I’ve already try to get from forums and wiki some information before posting.

I’m trying to make constructive topic, treated it as such.

Here is the list of same of the pages that I’ve check before asking:

http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Reference_Count_and_AutoReleasePool_in_Cocos2d-x
http://www.cocos2d-x.org/projects/cocos2d-x/wiki/How_to_optimise_memory_usage
http://www.cocos2d-x.org/boards/6/topics/4908
http://www.cocos2d-x.org/boards/6/topics/678

Situation :

I’ve been developing in Cocos2d-x for some months and now my cross platform game begin to grow.

I’m really worry about memory, special in device with low memory, and I searching for best approach.

I’m doing a very complex menu scene that has own graphics, images, sound, music, and so on.

From menu scene I’m switching to game that actual has its own graphics, images, sound, musics, etc.

Each scene will have really strong memory usage.

Questions

Q1 : Two big scenes and transitions

I’m switching scenes using transitions, my investigation so far is until the transitions is end both scenes are running at the same time. I believe they running in a render texture and them bill draw with the transitions effects on the screen.

Then I need to have enough memory to have both things running at the same time.

xxx = memory used by MenuScene
yyy = memory used by GameScene
zzz = memory used by transition effects (no really much)

Stage 1: MenuScene : running using xxx memory
Stage 2: MenuScene GameScene : running using xxx+yyy+zzz
Stage 3: GameScene : running using yyy memory

And approach to reduce impact could be instead to going from MenuScene to GameScene is to go trough and loading scene that how only basic elements, just a color background and some “loading” text.

Them I could:

xxx = memory used by MenuScene
yyy = memory used by GameScene
www = memory used by LoadingScene (really low)
zzz = memory used by transition effects (no really much)

Stage 1: MenuScene : running using xxx memory
Stage 2: MenuScene LoadingScene : running using xxx+www+zzz memory
Stage 3: LoadingScene GamingScene : running using www+yyy+zzz memory
Stage 4: GamingScene : running using yyy memory

So in conclusion :

xxx+www+zzz < xxx+yyy+zzz
www+yyy+zzz < xxx+yyy+zzz

Is this approach right? Any problem with it?

Q2 : When release items.

If I do the approach in the 1st question a important point is when actual release the scene layer so its contents are release. (And as well clear unused cache textures and unload sounds).

In that approach could be the right place ::onExit of the Scenes to actual :

purge cached data, remove unused textures, remove sounds?.

As far as I understood, using the pool when the layer is destroy (is this actually happen?) all elements will have decrease they reference count and them release.

So if a try to unload unused texture onExit,are really unused at that point?

So basically, shall in init load all things mandatory for my scene (including preload of sounds), and them release (or force release) onExit?

Q3 : Temporary objects

In the game sometime we must display temporary objects, for example a explosion graphic.

Then we could just use in the action sequence create for that, movement, fade out, just add a CCRemoveSelf.

In that case all memory used by that sprite is properly clear, isnt it?

Of course not the texture but is ok since will be reuse several times.

Q4 : Reuse Particles emitters

Sometime we use particle emiters for temporary effects, setup as been remove after used,I believe that will clear is content but I’ve some question about performance and pre-loading.

If y create the particle system loading from a plist, but this loading will be happeng each time I need to emitted the particles. (Could be several emitters at a time).

Could be a better approach to in the scene init load one particle emitter, but not attach to the layer.

Call to retain, so is persistence.

When I need to draw the particles, use copy() and add to the layer, as well set-up auto remove on finish.

onExit from the scene release the original emitter.

Is this approach correct?

Q5 : CCString and formating

In a game you may try to format a string for any giving reason in several places, as for example trying to update your player score.

I saw in many places that people uses CCString::createWithFormat and them just getCString().

So since those CCString are not attached to the layer I don’t now when actually they memory will be released.

So a bunch of new allocs are done and I dont know when are actually release.

I was thinking several approach for this issue, fist have singleTone CCString to actually initWithFormat when I need to update the text. But I believe that initWithFormat may as well create the necessary memory space for the text, so could not be the best approach.

I was thinking just to have a char[SOME_CONSTANT_LENGHT] and use sprintf to actually format my text.

What should be the best approach?

Final :

Thanks to anyone that has read this long topic and feel free to answer no only the question, anything relevant for the topic.

Best way to figure that out is to create a log on the Destructor of each object you’re observing.

Lance Gray wrote:

Best way to figure that out is to create a log on the Destructor of each object you’re observing.

That’s true, but I was wondering about if my approach are correct or not, or what else could be done.

You can try to not use autorelease() and use retain() and release() yourself but that would make it more vulnerable to leaks. But at least, you got complete control of all the memory allocation in your game, in which you’re very concerned about.

Nevertheless, you can always trust the cocos2d-x garbage collector, as it’s pretty good considering it is a port of the NSAutoreleasePool.

Lance Gray wrote:

You can try to not use autorelease() and use retain() and release() yourself but that would make it more vulnerable to leaks. But at least, you got complete control of all the memory allocation in your game, in which you’re very concerned about.
>
Nevertheless, you can always trust the cocos2d-x garbage collector, as it’s pretty good considering it is a port of the NSAutoreleasePool.

I trust the garbage collector, in fact I like how the autorelease / release mechanism work, my question is just asking how other people, with more experience than I, have deal with this matter.

I really worry about having to big scenes in memory just for a transition, the right place were free unused memory that is no need, if using so much CCString::create its have any impact, how I could preload the particle systems, and so on.

I believe one thing is to just perform a little game than to build a “big” game with more complex requirements, resources and finally running on low memory/performance devices.

Maybe I worry to much and other developers does not care.

In my opinion good developers shpuld care and think about such things.
Here are my opinions about your approach and how I deal with them (or how I propably would when faced with them) :

Q1 : Two big scenes and transitions & Q2 : When release items.
The loading scene approach is quite sensible as it shows the user that your game is still working and did not froze.
I release everything in the destructor, as it is safely called after the transition ends. I don’t know about ::onExit();

Q3 : Temporary objects
AFAIK you’re right.

Q5 : CCString and formating
I use std::stringstream for this purpose, basically because I didn’t know about CCString when I started working with cocos2d-x, and secondly because the stringstream gets automatically destroyed when the function returns.

Pawel Lopusinski wrote:

In my opinion good developers shpuld care and think about such things.
Here are my opinions about your approach and how I deal with them (or how I propably would when faced with them) :
>
Q1 : Two big scenes and transitions & Q2 : When release items.
The loading scene approach is quite sensible as it shows the user that your game is still working and did not froze.
I release everything in the destructor, as it is safely called after the transition ends. I don’t know about ::onExit();

I’ll make some test to see how is working onExit, if not I’ll try on destructor as you indicate.

>

Q3 : Temporary objects
AFAIK you’re right.
>
Q5 : CCString and formating
I use std::stringstream for this purpose, basically because I didn’t know about CCString when I started working with cocos2d-x, and secondly because the stringstream gets automatically destroyed when the function returns.

Never tough about using stringstream, if any one could just explain how the CCString::create… works when they are just create for call ->GetCString(), when actually they going to be remove…
Thanks for your answer.

Has not anyone a idea for Q4?

Thanks

You mix videomemory and memory used by CPU, they are not the same. Graphics objects mostly consume videomemory, at programmer should care about this memory to run game on low-end devices. Programmer should not care about memory heap, he should only ensure that there are no memory leaks and circular references. Memory leaks can be excluded by smart pointers, circular references are separate subject, but there are 3 techniques to prevent them.

In order to avoid videomemory issues, use four rules:
# ensure that there are no memory leaks and circular references of CCNode subclasses, they allocate videomemory (at least until cleanup() called);
# do not create a few CCRenderTexture instances immediately (PowerVR videocard does not like this), render a few objects to one texture instead and use CCSprite::create(CCTexture2D *, CCRect) (I hope everyone knows that in OpenGL you can easily render only part of texture because there are texture coordinates; cocos2dx uses this fact);
# pack textures into sprite sheets
# (hard task) compress sprite sheets to some texture compression format; one some videocards compressed texture stays compressed even after it was passed to OpenGL (it happens if videocard supports hardware accelerations of this texture compression format).

Lance Gray wrote:

You can try to not use autorelease() and use retain() and release() yourself but that would make it more vulnerable to leaks. But at least, you got complete control of all the memory allocation in your game, in which you’re very concerned about.
>
Nevertheless, you can always trust the cocos2d-x garbage collector, as it’s pretty good considering it is a port of the NSAutoreleasePool.

But it’s better to use special smart pointer for member variables and in asynchronous tasks (like loading something from URL).

As Sergey already mentioned it’s important not to mix videomemory (or texture memory) and heap memory. When you create a Sprite in Cocos2d-x it “holds” the texture and if you leak the Sprite (which itself is not really a problem) you won’t be able to release the corresponding texture (and that’s a problem). I just finished developing a Hidden Object game where you have to load a bunch of spritesheets for every scene and I had a lot of PITA fighting memory issues. Regarding your questions:

  1. This is a correct approach but the sequence of actions is a little bit more complex:
    a. create the transition to the Loader scene
    b. send notification from the destructor of the current scene
    c. receive the notification in Loader scene and remove unused textures from video memory
    d. load new textures
    e. run the next scene

I assume that when destructor is called all the Nodes corresponding to current scene are released, so nothing “holds” the textures and you can safely remove them. The reason why you need notifications here is that Loader scene will be created before the nodes from previous scene are released, so trying to remove textures just when you enter Loader scene won’t have any effect.

  1. Nodes are not released onExit(). It is called when you transition from one scene to another, but all the Nodes from the previous scene are still there, trying to get rid of unused textures at this point is generally a bad idea. You should not manually release Nodes, it’s all done by autorelease mechanism, the exception may be the CCArrays. I usually release them in destructor.

Next thing: if you try loading resources in init() the performance of your game won’t be smooth. Graphic resources should be loaded before you’re attempting to use them, Loader scene with some static content (e.g., “Loading…” label on a black screen) is a perfect place for that, performance jumps caused be texture loading won’t be visible to user.

  1. If the explosion is the same maybe you can reuse that sprite.

  2. I’m not sure if using copy will give you significant speed growth. If the effect is something like an explosion maybe it’s better to simply reuse the same emitter without deleting it or creating copies.

  3. I use C++ strings. It you need to create a C-string from it - no problem, just call cstr() member function.

Sergey Shambir wrote:

You mix videomemory and memory used by CPU, they are not the same. Graphics objects mostly consume videomemory, at programmer should care about this memory to run game on low-end devices. Programmer should not care about memory heap, he should only ensure that there are no memory leaks and circular references. Memory leaks can be excluded by smart pointers, circular references are separate subject, but there are 3 techniques to prevent them.
>
In order to avoid videomemory issues, use four rules:
# ensure that there are no memory leaks and circular references of CCNode subclasses, they allocate videomemory (at least until cleanup() called);
# do not create a few CCRenderTexture instances immediately (PowerVR videocard does not like this), render a few objects to one texture instead and use CCSprite::create(CCTexture2D *, CCRect) (I hope everyone knows that in OpenGL you can easily render only part of texture because there are texture coordinates; cocos2dx uses this fact);
# pack textures into sprite sheets
# (hard task) compress sprite sheets to some texture compression format; one some videocards compressed texture stays compressed even after it was passed to OpenGL (it happens if videocard supports hardware accelerations of this texture compression format).

You are right in a couple of element, but maybe its my misunderstood of things.

As far as I know in a mobile device you do not have video memory and graphics memory since all memory is share, so there is not vram and ram as in a other platforms. Maybe I’m wrong but all your memory could be used to load texture, as far as you have memory.

I know that we don’t need to take care of the heap, but I don’t know how actually the release mechanism work. So in normal c++ program if I create std::string object in a function there is nothing that really matter when the function end. But in Cocos we use the autorelease mechanims, If I understand it correctly the cstring::create (that actually is not attach to any node) will have its own retain count not related to the node where was crated, will be the function itself?, so I really wonder when is free. So If I create a ccstring:create in a cclayer to just update the score, when the memory allocate with new will be free?.

I’m already packing & compressing.

I’ve take good care of any memory leek and circular references.

Thanks for your answer.

Victor Komarov wrote:

As Sergey already mentioned it’s important not to mix videomemory (or texture memory) and heap memory. When you create a Sprite in Cocos2d-x it “holds” the texture and if you leak the Sprite (which itself is not really a problem) you won’t be able to release the corresponding texture (and that’s a problem). I just finished developing a Hidden Object game where you have to load a bunch of spritesheets for every scene and I had a lot of PITA fighting memory issues. Regarding your questions:
>

  1. This is a correct approach but the sequence of actions is a little bit more complex:
    a. create the transition to the Loader scene
    b. send notification from the destructor of the current scene
    c. receive the notification in Loader scene and remove unused textures from video memory
    d. load new textures
    e. run the next scene
    >
    I assume that when destructor is called all the Nodes corresponding to current scene are released, so nothing “holds” the textures and you can safely remove them. The reason why you need notifications here is that Loader scene will be created before the nodes from previous scene are released, so trying to remove textures just when you enter Loader scene won’t have any effect.
    >
  1. Nodes are not released onExit(). It is called when you transition from one scene to another, but all the Nodes from the previous scene are still there, trying to get rid of unused textures at this point is generally a bad idea. You should not manually release Nodes, it’s all done by autorelease mechanism, the exception may be the CCArrays. I usually release them in destructor.
    >
    Next thing: if you try loading resources in init() the performance of your game won’t be smooth. Graphic resources should be loaded before you’re attempting to use them, Loader scene with some static content (e.g., “Loading…” label on a black screen) is a perfect place for that, performance jumps caused be texture loading won’t be visible to user.

I was exactly looking this approach, I’ve notice that onExit (from layer) its actually calling the destructor of the layer, but the children of the layer are not been remove when the layer its actually deleted.

>

  1. If the explosion is the same maybe you can reuse that sprite.

Yes but the problem is that several explosions are create at the same point so you could just not use “one” explosion, the texture can be reused (as is cached) but not the sprite itself.

>

  1. I’m not sure if using copy will give you significant speed growth. If the effect is something like an explosion maybe it’s better to simply reuse the same emitter without deleting it or creating copies.

The problem as bellow question that this is happen at the same time several time, so I need more that one emitter. In other part of the application I get your approach and have only 1 emitter been reset when I need it.

>

  1. I use C++ strings. It you need to create a C-string from it - no problem, just call cstr() member function.

An option as well but sometimes I’ve trouble to decide to use std versus cocos classes, ccarrays vs std::vector, ccstring versus std::string.

Thanks

Both for sprites and particle systems you can create pools. If you have any guesses about how many sprites/emitters you need - init the pool with this number of corresponding objects, if you’re suddenly out of bounds - just add another one, when the sprite or emitter is done - mark it as free. I usually try not to create anything during the run.

Concerning Cocos Cocoa vs STL - well, it’s up to you of course, but I think if you can use STL - use STL.

I was exactly looking this approach, I’ve notice that onExit (from layer) its actually calling the destructor of the layer, but the children of the layer are not been remove when the layer its actually deleted.

When onExit() member function of CCLayer is called CCDirector removes it from delegate list of touch~~, accelerometer~~ and keypad dispatchers, onExit() has nothing to do with deleting Nodes. What does is a destructor of the Scene’s parent class Node, called by autorelease mechanism when CCDirector run the next scene. In the Node’s destructor CCArray containing it’s children is being released and all of it’s contents are released as well - that’s the point when you can safely remove graphical resources from memory.

Lance Gray wrote:

You can try to not use autorelease() and use retain() and release() yourself but that would make it more vulnerable to leaks. But at least, you got complete control of all the memory allocation in your game, in which you’re very concerned about.
>
Nevertheless, you can always trust the cocos2d-x garbage collector, as it’s pretty good considering it is a port of the NSAutoreleasePool.

Did I’ve just read that Cocos2d-x has garbage collection? :S

I think you misunderstood what a garbage collector is there…
If you do this you’ll have a leak:

void someMethod()
{
    CCSprite* sprite = CCSprite::create("texture.png"); // autorelease gets called here
    sprite->retain();
}

A garbage collector registers the existance of all references and objects and builds a tree with them.
The objects that are not in that tree are not referenced anywhere and garbage collector removes them.
If there was a garbage collector you won’t be having a leak there, but since there is not, you have one.

Other than that, I’m not a big fan of autorelease, as it’s not thread safe (it’s using a collection that’s not prepared to be used concurrently).