first defined a class:
class C1 extends Sprite
{
public function C1() { super(); }
}
then write the following codes in Document Class:
setInterval(function(a:Sprite):void {
a.addChild(new C1());
}, 10, this);
setInterval(function(a:Sprite):void {
a.removeChildAt(0);
}, 11, this);
then run it and check the memory ustage, it will get more and more larger...
how could released the memory when remove the child from root?
The Flash VM uses garbage collection to free up memory. GC will be executed at arbitrary times by the player, unless you explicitly call System.gc(), but this method is available in AIR and the debugger version of Flash Player only. Therefore, usage of memory might still continue to increase, even though you have freed up resources in your program, until the GC process is executed.
Also, note that addChild() and removeChild() merely add and remove items to and from the display list. To really free up a resource, you have to explicitly set all references to it retained in your program to null.
Related
I have a game which does not/cannot use a "Loading Screen". I'm having some trouble using AssetManager to load assets on the fly after an Ad shows, or an IAP process happens - essentially whenever the OpenGL context changes.
I've followed the wiki article on AssetManager, but I'm still seeing black textures whenever I try to load a "new" texture.
I have a Singleton custom GameAssetManager which has some convenience methods which delegate to LibGDX's AssetManager.
For example:
public Texture getTexture(String filename) {
if (assets.isLoaded(filename)) {
return assets.get(filename, Texture.class);
} else {
assets.load(filename, Texture.class);
assets.finishLoadingAsset(filename);
Texture texture = assets.get(filename, Texture.class);
sessionAssets.put(filename, texture);
return texture;
}
}
In my AndroidLauncher, I override the onResume method like so:
#Override
protected void onResume() {
super.onResume();
GameAssetManager.instance.resume();
}
The GameAssetManager.resume() method just does this:
public void resume() {
assets = new AssetManager();
Texture.setAssetManager(assets);
}
I have a StoreItemButton which is a Group and which changes it's layout/ui-components when the item is purchased through Google's IAB library or an Ad shows.
After the Ad shows, or the IAB process completes AndroidLauncher.onResume is called and when the button changes it's UI it or parts of it just turn black.
If I go through and pre-load all possible layouts - up to 4 per button (up to 30 buttons), and then just show/hide them based on the situation, it seems to work, but this is a lot of overhead and error prone for no good reason.
Any help here would be greatly appreciated.
The short explanation is that while your application may see texture references on the JVM heap as valid, the real texture bytes in the GPU may be invalid.
This often happens onPause, because another activity or process may take the OpenGL context to draw itself and everything that your program has put to the GPU may be discarded. When the program resumes after that (onResume), your variables holding the textures may not be destroyed and may still point to valid JVM heap objects (either because you have static refs, or because the Gargabe Collector has not claimed anything), but the textures in the GPU are gone and should be pushed/reloaded there again.
This is the article that can give you a more complete answer, directly by the libgdx "benevolent dictator" :)
http://www.badlogicgames.com/wordpress/?p=1073
I just discovered nested functions in AS3 (yeah, late to the party) and am using them in a Flex project. I've always disliked having to use separate functions for essentially modal operations with eventListeners– adds clutter to code and separates operation logic, as well as not being able to easily reference local variables.
The example below for a user selecting a directory seems to work very well and is nice an compact but I am wondering if there are any issues I am not aware of with this approach. Also, with a non-modal operation (e.g. asynchronous like using a Loader), is it possible to use nested functions?
private var rootDirectory:File;
protected function rootBtn_clickHandler(event:MouseEvent):void
{
var tmp:File = File.desktopDirectory;
tmp.browseForDirectory("Set Project Folder");
tmp.addEventListener(Event.SELECT, onUserSelect);
tmp.addEventListener(Event.CANCEL, onUserCancel);
function onUserSelect(event:Event):void
{
tmp.removeEventListener(Event.SELECT, onUserSelect);
tmp.removeEventListener(Event.CANCEL, onUserCancel);
rootDirectory = event.target as File;
}
function onUserCancel(event:Event):void
{
tmp.removeEventListener(Event.SELECT, onUserSelect);
tmp.removeEventListener(Event.CANCEL, onUserCancel);
trace("user canceled");
}
}
There can be some caveats when using anonymous or nested functions.
The first and most important is garbage collection:
In your example, the only thing keeping your tmp object from being garbage collected is the SELECT and CANCEL listeners themselves. Since you are not setting the weak flag to true, this shouldn't be a problem, however, if you we're using the weak flag (tmp.addEventListener(Event.SELECT, onUserSelect,false,0,true)) then there is a decent change the tmp object would get garbage collected before the user SELECTS or CANCELS a file.
Also, it's imperative that you remove every listener that you attached in this way. You are doing that in your onUserCancel method, so it should be fine, but if you were not, then you would have a memory leak on your hands as every time your click handler ran, another instance of tmp would be created but it would never get garbage collected because of the listeners attached to it.
So to summarize, most people stay away from anonymous/nested methods in AS3 (and I generally/usually recommend that to people) because it's easy to create memory leaks or have your closures garbage collected by accident. There also may or not be performance differences, but I have never ran tests in that regard.
I have a game that dynamicaly loads another minigame.
I load it using SWFLoader:
function loadMinigame(minigameName:String):void
{
var loader:SWFLoader = new SWFLoader;
loader.load("/Content/Swf/" + minigameName + ".swf");
layerMinigames.addElement(loader);
}
The first time I load it works nice. But when I exit the minigame and try to open it again via same method it doens't apper in my application (sometimes do sometimes doens't).
Both games are Flex application.
What's going on?
Update
I did loader.loadForCompatibility = true and now it loads properly! But now I'm getting an error when I try to cast the result:
loader.addEventListener(Event.COMPLETE, function(e:Event):void
{
var sys:SystemManager = SystemManager(e.currentTarget.content);
});
gives:
TypeError: Error #1034: Type Coercion failed: cannot convert
_AppMinigame1_mx_managers_SystemManager#14c97eb9 to mx.managers.SystemManager.
You'd better cache the loaded minigame after loading, then just display it again when needed. Make sure though, that the minigame's ADDED_TO_STAGE listener resets the minigame properly.
static var loadedGames:Object={};
function loadMinigame(minigameName:String):void
{
if (loadedGames[minigameName]==null) {
var loader:SWFLoader = new SWFLoader;
loader.load("/Content/Swf/" + minigameName + ".swf");
loadedGames[minigameName]=loader;
loader.addEventListener(Event.COMPLETE,loaderFinished);
} else {
layerMinigames.addElement(loadedGames[minigameName]);
}
}
function loaderFinished(e:Event):void {
layerMinigames.addElement(e.target);
// do the rest, like setting proper start time for minigame, etc
}
UPDATE: Since you run out of memory while running such a process, this means that the minigame's instance holds onto too much memory, and needs to be freed (GC'd) in order to load another minigame. Thus, caching loading SWFs is out of question. You can release an SWF using unloadAndStop() call against it, prior to doing this, make sure that your minigame is removed from display list, and its REMOVED_FROM_STAGE listener shuts down every listener attached to stage. Also you might need to debug your minigame SWF to locate probable memory leaks, as your SWFs share the same memory space, and a memory leak in one of them nullifies your efforts to do anything in all the others.
I am switching scenes when my character wins or loses the game. I get a message saying a pointer being freed was not allocated.
Sometimes, the game does not crash and it goes back to the game view. But sometimes the game crashes in the main on this line:
int retVal = UIApplicationMain(argc, argv, nil, #"AppController");
the error being "bad access";
I switch to the end screen using the CCdirector:
cocos2d::CCDirector::sharedDirector()->replaceScene(GameWon::scene());
Then in the GameWon.cpp I create a new game scene to start a new game:
cocos2d::CCDirector::sharedDirector()->replaceScene(Controller::scene());
No idea what causes this problem. The weird thing is that, it doesn't always crash on the simulator. Any tips?
edit
So I found out what the problem is, I just don't know why it's a problem. Apparently the destructor of my Controller is called when I create a new scene. In this destructor I free my model object:
Controller::~Controller()
{
free(pModel);
}
When I don't free the model object it works like a charm. However, in the init of my constructor I do this:
pModel = Model::create();
So I'm not sure why the pModel would be a pointer that is being freed, but not allocated?
My guess is that you did not retain retain your pModel object. Create function usually autoreleases the object and if you do not retain it, it will be deleted by the time you call "free(pModel)" in the destructor.
you need not to free your pModel object manually in the destructor as in the create function the object being created is added to the autorelease pool . So what happens here is that first when the autorelease pool drains it automatically deallocates the memory allocated to the pModel . And when the controller's destructor is called free(pModel); tries to free the memory which is already freed.
When you replace scene, The destructor of previous scene is called. If you free the object created with create() function of cocos, as it’s already added in autorelease pool managed by cocos, pool tries to release (delete) already deleted(in destructor using free) pointer. so, Don’t use manual delete to cocos objects created using create functions.
I'm working on a Flash game, and after running my game for a while there is a huge drop in frame rate. There aren't a lot of MovieClips onscreen at once, but MovieClips are being replaced using removeChild and addChild often.
How can one test for problems such as memory leaks? And what are some good AS3 programming standards on this matter?
It seems like you're not preparing your instances of MovieClip for garbage collection. This thread could be extremely helpful to you.
Some of the basic things you want to cover when discarding a MovieClip (or any other Object) properly are:
Remove the object from the DisplayList (if it's a DisplayObject). This is done via what you're doing already, removeChild()
Remove any event listeners that have been applied to the Object. Best thing to do is keep on top of this right from the beginning; by that I mean, when you call addEventListener(), be sure to somewhere in the very near future add a sister removeEventListener() as well.
Remove reference to your Object. This includes, but is not limited to: reference to the Object via being part of an Array/Vector, reference via being stored in a property of another Object, etc.
A suggestion that I can offer is to have in the base class of your objects a method that handles all of this, eg remove() or deconstruct().
Here's an example:
public function deconstruct():void
{
if(parent)
parent.removeChild(this);
removeEventListener(MouseEvent.CLICK, _onClick);
}
And when you extend this class and need other dereferencing features, just build on your deconstruct() method:
override public function deconstruct():void
{
removeEventListener(MouseEvent.MOUSE_OVER, _mouseOver);
var i:int = someArray.indexOf(this);
someArray.splice(i, 1);
super.deconstruct();
}
http://gskinner.com/talks/resource-management/