Can recreating a new variable inside a timer object decrease performance? - actionscript-3

Hey everyone so I was wondering if recreating a variable movie clip inside a timer object every time it's called could decrease performance or cause a MEMORY LEAK. This is how I have it set up right now:
private function addSwimPowerUp(e:TimerEvent):void
{
var newSwimPower:mcSwimPower = new mcSwimPower();
stage.addChild(newSwimPower);
aSwimPowerUpArray.push(newSwimPower);
}
I do that with all my timer objects in my game. Should i just declare the var newSwimPower a private variable?

Creating a new instance of something and then not doing anything with it will result in its eventual garbage collection. That is, if your code was this:
private function addSwimPowerUp(e:TimerEvent):void
{
var newSwimPower:mcSwimPower = new mcSwimPower();
}
Then all of those new MovieClips will get cleant up.
With that said, you're adding those objects to the display tree as well asn an array. If you do not remove the object from both of those things, it will not get garbage collected and that will be a memory leak.
Creating a class level variable for newSwimPower and assigning to that instead won't make any difference, other than that if you don't garbage collect the class referencing it then the last instance you created will still be in memory.

Related

Using retain and release for Objects

Are there any general guide lines for using retain and release for objects in cocos2d-X ? When creating objects in a function, is it true that the functions memory is cleaned up the second the function returns. When a object is created, calling the retain function of the object, will retain object beyond the function return ?
Kind Regards
Generally in c++ you have this behaviour:
void foo() {
Object a;
Object *pA = new Object();
(…)
}
This would result in a being destroyed automatically at function end, as it was allocated on stack. The *pA would not get destroyed, as it was allocated on the heap (thus, you only loose the reference to it, but the object itself still lives).
Cocos implements a thing called "Automatic Reference Counting" : each CCObject has a reference counter and two methods retain() and release(). The way this works is, that every time you create an object, it gets registered in cocos structers (CCPoolManager). Then with every frame (between them being drawn) there is a maintenance loop which checks the reference counter of all objects : if it is 0 this means (to cocos) that no other objects reference it, so it is safe to delete it. The retain count of an object is automatically incresead when you use this object as an argument for an addChild function.
Example :
void cocosFoo() {
CCSprite *a = CCSprite::create(…);
CCSprite *b = CCSprite::create(…);
this->addChild(b);
}
What happens here is this :
Two CCSprites are created, cocos knows about them.
The b sprite is added to this object (say a CCLayer)
The function ends, no objects are destroyed (both of them being on heap).
Somewhere between this and next frame, the maintanance gets run. Cocos chcecks both sprites and sees that a has reference count == 0, so it deletes it.
This system is quite good, as you don't need to worry about memory management. If you want to create a CCSprite (for example), but not add it as a child yet, you can call retain() on it, which will raise its reference counter, saving it from automatic deletion. But then you'd have to remember about calling release() on it (for example, when adding it as a child).
The general things you have to remeber about are :
Each call to retain() by you needs to be paired with release().
You generally shouldn't delete CCObjects yourself. If you feel that you need to, there is a conveniece macro : CC_SAFE_DELETE(object)
So to answer your questions in short :
Are there any general guide lines for using retain and release for objects in cocos2d-X ?
Yes, you should generally not need to do it.
When creating objects in a function, is it true that the functions memory is cleaned up the second the function returns.
Answer to this is the whole text above.
When a object is created, calling the retain function of the object, will retain object beyond the function return ?
Yes, as will adding it as a child to another (retained in any way) object.
Here is the thing,
cocos2dx has an autorelease pool which drains the objects which have retain count=0 which is a variable to keep in check the scope of the cocos2dx object.
Now when you create new object using the create method it is already added to the autorelease pool and you don't need to release it or delete it anywhere , its like garbage collector in java, takes care of garbage objects behind your back.
But when you create new object using 'new' you definitely need to release it in its destructor or after its use is over.
Second thing,
when your object is added to the autorelease pool but you need it somewhere else you could just retain it , this increments its retain count by one and then you have to manually release it after its use is over.
Third Thing,
Whenever you add child your object it is retained automatically but you don't need to release it rather you remove it from the parent.

Instantiating in Array

I have these three objects that i need to add on stage, when I extract them from the array on a later stage of the program.
I can't write var mall: Mall = new Mall (); because somebody told me before that, This will add in the object in the memory and will be really bad if a lot of objects are being handled. I will have a lot more objects to work with later on.
So I would like to know a way that when i run a for loop or an event listener i can add ... = new object (); automatically and then call addchild to make an instance of the object.
var mall:Mall;
var library:Library;
var music:Music;
var choices:Array = new Array ();
choices.push(mall,library,music);
test Code for Garbage Collection :
var waking: WakingUp = new WakingUp ();
addChild (waking);
waking.y=-30;
waking.addEventListener (Event.ENTER_FRAME, waking_up);
function waking_up (g:Event){
if (waking.currentFrame == waking.totalFrames)
{
waking.stop ();
waking.removeEventListener (Event.ENTER_FRAME,waking_up);
removeChild (waking);
removeChild(alarm_slide);
gotoAndStop (6);
}
}
This is all the ref I have to this code :D
Specific to instantiating your array with elements, you can:
var choices:Array = [ mall, library, music ];
Flash Player runtime uses both reference counting as well as mark and sweep.
So, any reference to the instance adds a count - collections, display list, event listeners, class members... as instances are dereferenced, the memory will ultimately be freed.
Reference Counting
Each object on the heap keeps track of the number of things pointing to it. Each time you create a reference to an object, the
object's reference count is incremented. When you delete a reference,
the object's reference count is decremented. If the object has a zero
reference count (nothing is pointing to it), it is added to the Zero
Count Table (ZCT). When the ZCT is full, the stack is scanned to find
any references from the stack to an object on the ZCT. Any object on
the ZCT without a stack reference is deleted.
One of the problems of deferred reference counting is circular references. If ObjectA and ObjectB refer to each other but no other
objects in the system point to them, they will never have a zero
reference count and will therefore never be eligible for garbage
collection using reference counting. This is where mark and sweep
garbage collection helps.
Mark/Sweep
Applications that run in Flash Player or AIR have multiple GCRoots.
You can think about a GCRoot as the trunk of a tree with the objects
of the application as the branches. The Stage is a GCRoot. Loaders are
GCRoots. Certain menus are GCRoots. Every object that is still in use
by the application is reachable from one of the GCRoots within the
application. GCRoots are never garbage collected.
Every object in an application has a "mark bit." When the Mark phase
of garbage collection begins, all of those mark bits are cleared. The
MMgc keeps track of all GCRoots in the application. The garbage
collector starts from those roots, traces through each object and sets
the mark bit for every object it reaches. Any object that is no longer
reachable from any of the roots is no longer reachable from anywhere
in the application – its mark bit does not get set during the Mark
phase. Once the collector is done marking all of the objects it finds,
the Sweep phase begins. Any object that doesn't have a set mark bit is
destroyed and its memory reclaimed.
addChild does not make an instance of the object, it simply adds the object to the displaylist of the current display container.
Using new Mall() is fine - just ensure that you remove references to it when it's no longer required so that it may be garbage collected. Alternatively you can just hold an array of primitives.

how to disable garbage collector as3 [duplicate]

This question already has answers here:
disable GC in AS3
(2 answers)
Closed 9 years ago.
so, I am making really enormous project with as3, and I`d like to know how to disable garbage collector, as user might be on for long and I dont want him or her to just be cut off because garbage collector removed some listener somewhere that should be now needed.
is there easier way to disable garbage collector than go to every single listener and add "false, 0, true" extension after naming the listener?
No it's not possible, but what you're afraid of isn't really an issue.
Also, making event listeners weak doesn't disable the garbage collector, in fact it makes whatever object they are set to eligible for garbage collection if that is the only reference left to them.
That is possible actually, but it needs discipline...
When an as3 object looses all its references to others, it becomes a candidate for garbage collection. To avoid this you can use the following method:
When you need an object to persist in memory, bind it to somewhere accessible.
Here I supplied an example code.
First create the class below:
package your.package.path;
public class noGc {
protected static var vault:Array = [];
// In case we forget that noGc should stay static....
public function noGc(){throw new Exception('Error: Instance from STATIC noGc');}
public static function hold(o: *): void {
if(vault.indexOf(o)==-1)vault.push(o); // no multiple references in vault
}
public static function release(o: *): Boolean {
var i: int = vault.indexOf(o);
if(i == -1)return(false); // return value is for information only
vault.splice(i,1); // remove object from vault
return(true);
}
public static function releaseAll(): void {
vault.length = 0;
}
} // end class noGc
To avoid gc on "yourObject"
noGc.hold(yourObject);
To allow gc on "yourObject" back
noGc.release(yourObject);
For normal code flow start holding the objects right after creation of them.
Then you should release them at the end of their use.
Also you have to keep an eye on exceptions since exceptions break the normal flow you should handle them and release the objects becoming irrelevant after the exception.
Forgetting an object held means use of unnecessary memory, a.k.a. a memory leak.
As I told before, It needs discipline.
Finally, when you need to wipe all objects that are held use,
noGc.releaseAll();
Hope this helps.

How do I pass reference of an initialised object from one class to another class, to add (addChild) to display list?

I created this simple example
because I was using a more complex class, a menu item that I wanted to initialise all the settings in the Main class and then add it in in the Game class (and updating it) when needed (both classes are separate)
Class: Main (document class, is (ideally) where everything is initialised/created)
public class Main extends MovieClip
{
//testing passing on reference to Game
private var testBitmap:Bitmap;
private var testBitmapData:BitmapData;
private var testArray:Array;
public function Main():void
{
testBitmapData = new BitmapData(256, 256, false, 0xCCDDEE);
testBitmap = new Bitmap(testBitmapData);
testArray = [];
testArray.push(testBitmap); //Array for reference
game = new Game(540, 960, testArray);
//create Game class, pass reference to Object
game.x = 0;
game.y = 0;
}
}
Class: Game (created by document class, is (ideally) where everything runs)
public class Game extends MovieClip
{
private var testingArray:Array
public function Game(gameWidth:int, gameHeight:int, testArray:Array):void
{
this.testingArray = testArray; //assign to local Array and access
addChild(testingArray[0]);
//addChild to Game from an item intialised in Main, doesn't work >___<
}
}
.
.
.
the thing is, in my original Game class; it receives an initial bundle of cached BitmapData and a list Array that tells it which BitmapData it needs to cycle through
cut-down here (and that reference only for updating works (if I addedChild in Main already):
public function Game(gameWidth:int, gameHeight:int, cachedBitmapClipArray:Array)
{
this.cachedBitmapClipArray = cachedBitmapClipArray;
private function update():void
{
for each (tempCachedBitmapClip in cachedBitmapClipArray)
{
tempCachedBitmapClip.updateCurrentTile();
//but updating through the reference to an item initialised in Main works !!
}
}
}
.
how do I make the reference and passed in objects (or have access to) behave as in the original instance ?? (being able to addChild)
i.e. can objects cross 'scopes' (??) or should objects only be controlled (instantiated) in the class where they have been initialised
Well to answer the last question, yes objects can be passed from one object to another. I'm having a hard time understanding what exactly the problem is though. In generic programming terms Object or any other complex type are passed by reference, primitive types are also passed by reference but the internals of the AVM handle them in such a way as to treat them as passed by value. For a pretty clear (in my eyes at least) explanation of how arguments are passed via function/method calls, read here:
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f56.html
Check out other areas in the tree navigation on the left for more details on the language itself.
One thing to note though I think the compiler will work around this error, in the first bit of code you posted Game has a return value of :void for a constructor there should be no declared return type since it should be implicitly typed as whatever the class is.
To add some explanation in my own words regarding pass by reference or pass by value. Pass by value means that the value of the object, that is the bytes stored at the location pointed to by the variable are actually copied to a new memory location which is then used. What this means in practice is they are not the same bytes of memory but rather they are two separate memory locations each with the same value stored in them, modification of one value after the passing doesn't affect the original. Pass by reference is to say you pass the memory location therefore no new memory for the value is allocated, both values are actually pointing to the same memory location (the pointer to them itself may be different but that pointers both point to the same location in memory). In this case the objects are the same.
What you're doing is advisable, dividing the labor and enapsulating particular types of functionality in classes does make the code easier to work with. I think the only problem would be if the Game object itself is never added as a child to something in the display tree (something that is attached to the stage). It appears you're creating a new Game and setting it's position but never adding it as a child to the stage, then adding anything to Game is never a part of the display tree.

AS3 Memory Leak Example

Can someone post an example of as3 code (specifically event listener included) that would be a simple example of something that could leak memory... also hopefully could you post a solution to the problem shown?
The question is: What is a simple example of leaking memory in an AS3 event listener and how can you solve it?
public class MySprite extends Sprite {
public function MySprite() {
if(stage) {
init();
} else {
addEventListener(Event.ADDED_TO_STAGE,init);
}
}
private function init(e:Event = null):void {
stage.addEventListener(Event.RESIZE,handleStageResize);
}
private function handleStageResize(e:Event):void {
// do some processing here.
}
}
Somewhere else:
var mySprite:MySprite = new MySprite();
someHolder.addChild(mySprite);
Now, if at some later point you remove mySprite, it'll still hang around in memory, because it has added itself (or a reference to itself) to the stage in the init() method.
In this scenario, the best way to avoid this could be removing the listener added to the stage when mySprite is removed from the display list.
private function init(e:Event = null):void {
addEventListener(Event.REMOVED_FROM_STAGE,cleanUp);
stage.addEventListener(Event.RESIZE,handleStageResize);
}
private function cleanUp(e:Event):void {
stage.removeEventListener(Event.RESIZE,handleStageResize);
}
I'm sure other people will tell you to use weak references when adding the listener to the stage, but you should remove your listeners anyway. If you don't, when you remove mySprite from the display list and have no other refs to it, will be eligible for GC and will eventually be wiped away from memory. But until that happens, the code in handleStageResize() will continue to execute.
I'll just follow up #Juan's answer - GC needs to be considered from the ground up as a critical aspect of application design. If you create an object, you must be aware of each reference to it, and remove each reference and nullify it to flag properly#. If you reference that object in array, that counts, if you reference it in a listener, that counts, if you reference it via a local variable, that counts too (though only during the life of the function), if its simply in the display list, that definitely counts, and on and on.
I go so far as to write my remove listener statements prior to adding them just to make sure.
I will almost always write a public destroy() method for any object to handle inner object hierarchies (parent calls destroy on child, which, in turn calls destroy on any children etc etc). Just removing / nulling a parent without doing so to each child is poor GC management.
And if you actually have any concerns that mem leak has sprung, trace out System.totalMemory just to make sure:
var mem:String = Number( System.totalMemory / 1024 / 1024 ).toFixed( 2 ) + ‘Mb’;
trace( mem ); // eg traces “24.94Mb”
Mostly - just be methodical about it - its not rocket science, but you have to be careful.
Cheers -
# and even if you do, flash makes up its own mind about when to actually do a sweep. The best we can to is ensure an object is properly flagged and trust that it will be dealt with efficiently.
I'm not going to post an example of this but I'll explain it a bit. There are 2 situations you are describing here.
memory leaks
processor overflows
AS3 handles memory and processor operations differently.
Memory Leaks happen when there are many objects created and destroyed. The objects leak memory when they have references and the object is destroyed with out destroying the references - therefor leaving a memory block of an unused object = leak.
Processor Overflows happen when you have many methods referencing each other with out 'closing the loop'.