What keeps objects in local mode alive when registering listeners?

I see this type of apparent magic in all kinds of AS3 code, but here is an example:

package { import flash.display.Sprite; import flash.events.*; import flash.net.*; public class URLLoaderExample extends Sprite { public function URLLoaderExample() { var loader:URLLoader = new URLLoader(); loader.addEventListener(Event.COMPLETE, onComplete); loader.load(new URLRequest("example.txt"); } // 'loader' should fall out of scope here! private function onComplete(evt:Event):void { var loader:URLLoader = URLLoader(evt.target); trace ("Received data: " + loader.data); //unsure if removal below is necessary (since I don't //know where 'loader' itself is hiding!)... // - NOTE: this removal is never in the examples! loader.removeEventListener(Event.COMPLETE, onComplete); } } } 

As indicated in the code comment, the loader variable should fall out of scope after the URLLoaderExample constructor. However ... it is still alive (rather than garbage collection) somewhere since the onComplete listener / handler can get it cleanly.

Where is the magic / hidden / global loader link that supports it so that it can complete the load operation and then be passed to the onComplete listener / callback? Could this link be seen somewhere?

To help with the context ... as a similar example, I know that the loader instance will have a registered onComplete listener. I also know that I need to be careful when using removeEventListener at any time (?), To avoid potential memory leaks as a result of multi-user listeners. It bothers me that I do not understand where the loader magic link is located, and (or when) I need to clear it.

Perhaps this is a call to loader.load() that contains loader somewhere globally?

+8
flex actionscript-3
source share
4 answers

This example is definitely error prone since the bootloader may receive garbage collection before the download completes. When you subscribe to a COMPLETE event using the onComplete method, you create a link from for your URLLoaderExample class. And what you need to make sure that the GC does not damage the bootloader creates a link to .

GC never guarantees timely cleanup, even if you explicitly kill all links. ( See this post for resources on GC logic. ) But it can be rubbish to collect the bootloader in the process if there are no explicit references to It. If you try your test in an application that uses memory (and not just sitting there does nothing), you will most likely see this behavior. And you see a garbage collector much more often if you try to load swf instead of data.

Using weak links here does not help, because when you do this, you tell GC: "Feel free to kill that I, the dispatcher, refer to it, I do not regret it." In your example, it would look like this: “feel free to kill the instance of URLLoaderExample if it loses other viable links”, which, well, is pointless. Here is one good article about useWeakReference.

Students do not prevent the dispatcher from collecting garbage. An inactive object is one that no longer has references to it from other active objects. Thus, if the object itself has references to something external, it does not prevent the removal of this object from memory.

So, to answer your question in a nutshell: the link is nowhere, you just got lucky that the download is correct. Well, to be completely accurate, this is a function activation object (as it is called in the ECMA specification), which is used as a scope for local variables and refers to them. But anyway, he gets access to the return method, and you can never get a link to the activation object (again according to the specification).

EDIT A few more words about who keeps someone out of the trash. Posted due to obvious misunderstanding in the comments.

Quote from Adobe liveocs :

useWeakReference: Boolean (default = false) - determines whether the reference to the listener is strong or weak. A strong link (by default) prevents your listener from being garbage collected. There is no weak help.

So, subscribing to an event creates a FROM dispatcher TO listener link. And the dispatcher is free, unlike the listener. Listeners do not interfere with garbage collection. And the dispatcher MAY NOT allow the listeners to be garbage collected, so we have useWeakReference .

+5
source share

When you add an event listener, you implicitly create a reference to the loader object (by default). However, you can remove this by setting the eventlistener to a "weak" link.

Here's how you do it:

 loader.addEventListener(Event.COMPLETE, onComplete, false, 0, true); 

The last argument sets "useWeakListener" to true, which means that the link to the loader will not be executed. In this case, the bootloader should be GC'ed.

It is important to remember that if you add an event listener with a strong link, you need to remove it (as in the example). If you use a weak listener, you will need to make the loader a private variable in the class, otherwise your callback will be in a race with GC.

Here's the documentation for the method: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/IEventDispatcher.html

+1
source share

Well man, if your question is why the bootloader is alive out of scope, here is your answer:

In fact, the loader that you see in the class constructor (CCM) method is not the one you see in onComplete: LINE14: var loader:URLLoader = URLLoader(evt.target);

(I don’t know why people like to enter the same name into variables, which can be confusing, but now it’s not, if I explain)

The magic lies in evt.target . But you must ask yourself: "What does .target do?" Well, this is an instance variable defined by "Event Object", and contains a link to "Target".

If you do not know what the “Target” is, read this paragraph. "Target" is an object in which the listener is registered in LINE9: loader.addEventListener(Event.COMPLETE, onComplete); As you can see, this is the bootloader in CCM (please do not confuse the bootloader names), which refers to new URLLoader(); . Section Conclusion: “Target” is a URLLoader object referenced by the local load variable in the CCM.

Well, using the .target variable, you can have a reference to a URLLoader object, and then use the link as you want. In this case, you used the link to remove the listener. Everything is good.

Here is an improved version (only one instance variable that gives a link to URLLoader):

 package { import flash.display.Sprite; import flash.events.*; import flash.net.*; public class URLLoaderExample extends Sprite { private var lalala:URLLoader; public function URLLoaderExample() { lalala = new URLLoader(); lalala.addEventListener(Event.COMPLETE, onComplete); lalala.load(new URLRequest("example.txt"); } private function onComplete(evt:Event):void { trace ("Received data: " + lalala.data); lalala.removeEventListener(Event.COMPLETE, onComplete); } } } 

But just to make shure, you will not be confused with the names:

 package { import flash.display.Sprite; import flash.events.*; import flash.net.*; public class URLLoaderExample extends Sprite { public function URLLoaderExample() { var blabla:URLLoader = new URLLoader(); blabla.addEventListener(Event.COMPLETE, onComplete); blabla.load(new URLRequest("example.txt"); } // 'loader' fell out of scope here! and it fell look there private function onComplete(evt:Event):void { var phopho:URLLoader = URLLoader(evt.target); trace ("Received data: " + phopho.data); loader.removeEventListener(Event.COMPLETE, onComplete); } } } 

Greetings ... If you have any doubts about the casting operation used in URLLoader(evt.target); , you can ask.

+1
source share

I do not understand your confusion. The bootloader variable goes out of scope (as indicated, the link you specified in memory is no longer required). However, since there is still a link to an external event listener, the loader itself is not GC'ed, so you can continue to receive a link to the loader (in the handler, it gets the target) and will not be eligible for the GC until the event listener will not be deleted.

EDIT: Sorry, I should have figured this out more clearly. I should have had more coffee. When I mean “external,” I mean things like downloaders, because they depend on the browser. Now I can’t say it for sure, since I have never seen the base code for Flash Player, but my suspicion is that if you have classes like Loader that should interact with the browser, a link will be provided (from player to bootloader) which will stop him from gc'ed. This is why you should always unload your forklifts or so, this is my understanding of Flash Player. I could be wrong, but in the past I did some tests and I never saw an external listener (in this case Loaders, but I wonder if there are other external listeners that can happen with Air) to get the GC without being explicit.

0
source share

All Articles