My application creates a window with a few Groups. When the window is closed, the window and it's descendents are not collected by the GC.
The Flash Builder Profiler helped me find and remove event listeners to the point where i am unable to spot the problem, since it points to event listeners added from the library code of Window.as.
Specifically, comparing the Loitering Objects from before window open and after window close, and choosing the MyWin class (1 instance):
MyPackageName.MyWin (10 Paths)
10x the following line:
Function [savedThis] 569222 GCRoot:Yes bytes:308
Clicking each "Function" in the Method panel i see the following 10 at the top of each "Function":
spark.components:Window:creationCompleteHandler() Window.as line 2610
spark.components:Window:creationCompleteHandler() Window.as line 2613
spark.components:Window:creationCompleteHandler() Window.as line 2616
spark.components:Window:creationCompleteHandler() Window.as line 2619
spark.components:Window:creationCompleteHandler() Window.as line 2625
spark.components:Window:creationCompleteHandler() Window.as line 2639
spark.components:Window:creationCompleteHandler() Window.as line 2636
Spark.components.supportClasses:SkinnableComponent:attachSkin() SkinnableComponent.as line 694
Spark.components:SkinnableContainer:partAdded() SkinnableContainter.as line 959
Spark.components:SkinnableContainer:partAdded() SkinnableContainter.as line 957
All these are invoked from a MyWin.initialize() in some manner.
I have removed every event listener created by my code, and removed all transitions.
but still unable to figure the meaning of this and how can i dispose of the window.
Any help, would be greatly appreciated since I've been struggling for a few days now.
You can try to use
System.pauseForGCIfCollectionImminent(1)
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/System.html#pauseForGCIfCollectionImminent%28%29
or try to use
System.gc()
in this way
private var numCollected; uint = 0;
private function gCollect(): void
{
addEventListeners(Event.ENTER_FRAME, onEFGCollect);
}
private function onEFGCollect(event: Event): void
{
numCollected++;
System.gc();
if(numCollected > 2)
removeEventListeners(Event.ENTER_FRAME, onEFGCollect);
}
there we use System.gc() two times in separate frames just because to collect object it's need to mark all of them as collected - and only after that System.gc() can collect objects.
As far as I know the best way is to make sure all references to the window in question are set to null. I have looked into this before and could not find any direct way to get the garbage collector to work immediately.
Related
Hello I was wandering if someone could help, I keep getting this error spat back at me when I try to launch something in as3. Do I need to import something? Apologies, I originally learned AS2 and I'm now slowly learning AS3.
baby steps.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at draganddropframe1_resetter2_0_fla::MainTimeline/frame3()
at flash.display::Sprite/constructChildren()
at flash.display::Sprite()
at flash.display::MovieClip()
this.window_mc.visible = true;
this.windwo_mc.offwindow.addEventListener(MouseEvent.CLICK, shutwin);
function shutwin(event:MouseEvent):void
{
this.window_mc.visible = false;
}
UPDATES -----------
A method that appears to have worked around it by changing the direct path to 'this'. Clicked inside the movieclip, added a layer called actions and inserted this script that referenced the movieClip I wanted to hide when clicked.
this.addEventListener(MouseEvent.CLICK, fl_ClickToHide);
function fl_ClickToHide(event:MouseEvent):void
{
this.visible = false;
}
The error you are getting means an object, (moveiclip, variable, etc ) doesn't exist.
Go to your publish settings, and check the box that says "permit debugging". Then when you get that error in your output window it will also display the exact line number the error occurred on. That line will probably tell you what object is null.
It looks like you have a typographical error in your second line. This line
this.windwo_mc.offwindow.addEventListener(MouseEvent.CLICK, shutwin);
should be
this.window_mc.offwindow.addEventListener(MouseEvent.CLICK, shutwin);
You've interchanged w and o.
Otherwise, I would suggest doing Ribs's answer.
UPDATES ----------- "from me "
A method that appears to have worked around it by changing the direct path to 'this'. Clicked inside the movieclip, added a layer called actions, and inserted this script that referenced the movieClip I wanted to hide when clicked.
this.addEventListener(MouseEvent.CLICK, fl_ClickToHide);
function fl_ClickToHide(event:MouseEvent):void
{
this.visible = false;
}
Place this script inside the Movie.
I have been frustrated with this simple piece of code for quite some time now. I am just about to give up. Pretty much I am trying to make two objects react when they hit together, however I constantly get this error:
Scene 1, Layer 'hero', Frame 1, Line 27 1046: Type was not found or was not a compile-time constant: hit.
This is the Class file (that I am sure I am doing something wrong in to):
After reviewing your code, there doesn't seem to be anything wrong. With that said, one or more of the following may be causing your issue:
In File -> ActionScript Settings, you may have a value that is greater than 1 for this field:
Similarly, you may have unchecked this field 'Export in frame 1' when creating your symbol.
If the former, your symbol hit will not be available until your SWF has reached the frame that you entered. If the latter, your symbol hit will not be available until your SWF passes over a frame that you have placed it on.
The problem is in line:
var hit:hit = new hit();
You have a conflict of class name and instance, rename local variable and use it everywhere:
var hit1:hit = new hit();
I am trying to dispatch an event but not sure when I should do it to get the right results. The first event "submitClicked" is in the right spot and works great. However, the second event "dataReady" seems like it might be a problem.
I need it to be dispatched after this.compiledFormData is set.
Does AS3 wait for each line of code in a function to be executed before moving on to the next line?
// --------------------------------------------------------------------
public function submitForm()
{
//dispatch an event
var cEvt:FormRendererEvent = new FormRendererEvent( "submitClicked" );
cEvt.customMessage = "Started Submitting Form Data";
dispatchEvent(cEvt);
this.compiledFormData = JSON.encode(this.compileFormData());
var cEvt:FormRendererEvent = new FormRendererEvent( "dataReady" );
cEvt.customMessage = "Data is ready to be used";
dispatchEvent(cEvt);
}//end function
Yes, in AS3 each line must complete before the next line can run. When you dispatch events though, they will go off and do their own thing. So, your "main" code might complete, meanwhile your dispatched events could still be processing.
Each line of code is executed sequentially yes, but whether the implementation of the invoked API does something asynchronous is dependent on what API you're calling.
In this case JSON.encode is a synchronous operation and therefore will complete fully before the next line of code is executed.
I am extremely frustrated. I'm following a tutorial and mimicing it on my own. I have been able to sort out most of the errors so far but this one has me stumped. I have tried replacing all of the class files with the tutorial specimen ones but i still get the error.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.senocular.utils::KeyObject/construct()
at com.senocular.utils::KeyObject()
at com.asgamer.basics1::Ship()
at com.asgamer.basics1::Engine()
Now, not really understanding the error properly I paste dumped the files online for you to look at.
Ship class: textbin.com/78z35
Engine class: textbin.com/32b24
KeyObject class: textbin.com/p2725
As the error still occured when using the specimen class files I really have no idea where to begin. I will gladly try out any suggestions.
Tip: If you allow debugging, the exception will tell you the exact line in the source code where the Error is being thrown. Assuming you're using the Flash IDE, go to publish settings and in the Flash tab check "Permit debugging". This will makes thing much easier for you.
Anyway, you have an error message. If you read it carefully, you can narrow down where the problem is. I don't know if you are a programmer or you have any interest in being one; if you're not, this answer will hopefully solve this particular problem. Anyway, if you don't mind the rambling, let me tell you that if you're interested in becoming a better programmer, paying attention to errors and learning how to debug / troubleshoot problems is one of the most important abilities you need to develop (if not the most important one); so maybe this will give you a few hints you can use to solve other problems as well.
The message says:
Cannot access a property or method of
a null object reference.
This means, at some point, you did something like this:
someobject.someMethod();
or
someobject.someProperty = "foo";
And someobject happened to be null. You can't call methods or access properties of null.
Ok, so now you know, somewhere, a variable had null as its value. Notice that the fact that you define a variable of property doesn't mean it actually holds an object.
This just says that a variable called mySprite can hold an object of the type Sprite:
var mySprite:Sprite;
But until at some point you create a Sprite and assign it to mySprite, the value held by mySprite will be null. If you do:
mySprite.x = 0;
Before initializing mySprite (i.e. before assigning a Sprite to it), you will have this same Null Reference error.
This error message also offers some helpul context, which you can use to your advantage (in them old days... errors in Flash were silent; when things didn't work, you had to manually trace down the problem).
Ok, let's break this error message down:
at com.senocular.utils::KeyObject/construct()
at com.senocular.utils::KeyObject()
at com.asgamer.basics1::Ship()
at com.asgamer.basics1::Engine()
What you have above is called a stack trace. It basically tells you where the code blew up, and also gives you some context: how did you get there.
The first line tells where the error actually occurred. That is, the construct method in the KeyObject object. That method was called from the KeyObject constructor, which was in turn called from the Ship constructor, which was in turn called from the Engine constructor.
Now, let's analyze how you got there, following the stack trace, bottom-up:
Code in Engine constructor:
ourShip = new Ship(stage);
This creates a new Ship object. It passes a reference to the stage to the Ship constructor method.
Code in Ship constructor:
this.stageRef = stageRef;
key = new KeyObject(stageRef);
It grabs the ref passed in the previous step. It stores it and creates a new KeyObject object. The KeyObject constructor is passed a reference to the stage (which is the same ref that was passed from Engine to Ship).
Code in KeyObject constructor:
KeyObject.stage = stage;
keysDown = new Object();
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
Now we got to the point where the error message told you the problem was. So, somewhere, you are using a variable that holds null and trying to access one of its methods or properties.
This KeyObject stores the reference to stage it was passed in a static variable and creates a new Object object. So far, no problems. KeyObject cannot be null (it's a reference to a Class). The second line itself cannot have this null problem either. So, if this is all the code in that method, the problem has to be either in the third or the fourth line. Both access the stage reference you passed and try to call a method (addEventListener) on it. So if one fails, the other will fail as well. Then, the third line: that's where the problem has to be.
So, at that point stage is null. As said previously, you can't call a method on null, and that's what the error is telling you.
Now, if you get back to the first method call, you can see this is the origin of the problem:
ourShip = new Ship(stage);
You can be pretty sure that, at this point, stage was null. Add that to the fact that Engine extends MovieClip (which is in turn a DisplayObject), and to the fact that any DisplayObject has a reference to the stage object only while it's added to the display list. The conclusion: an instance of Engine was not attached to the display list when its constructor was ran.
A way to fix this (there might be others) could be moving the code in the Engine constructor to a separate function that will be executed only if / when the Engine object has a valid reference to the stage object.
public function Engine() : void {
if(stage) {
initialize();
} else {
addEventListener(Event.ADDED_TO_STAGE,initialize);
}
}
private function initialize(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE,initialize);
// here goes the code that's currently in Engine constructor
}
Hope this helps.
I have a feeling your stage property is null.
You have have to test this yourself with a trace of the stage object.
In the first line in the constructor of you Engine class, add:
trace(stage);
Add that just above this line:
ourShip = new Ship(stage);
If it traces "null" then that is your problem.
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'.