A Flash Developer Resource Site

Results 1 to 9 of 9

Thread: Should "local" variables/object ever need to be marked for garbage collection?

  1. #1
    Senior Member
    Join Date
    Mar 2003
    Location
    wishconsin
    Posts
    151

    Question Should "local" variables/object ever need to be marked for garbage collection?

    If I have a variable that is declared within a method of a class, should that variable EVER need to be marked for garbage collection (set to null).

    for example:
    Code:
    public class MyClass extends MovieClip
    {
         public function MyClass():void
         {
              //constructor
              myMethodThatLoadsAPage();
         }
         private function myMethodThatLoadsAPage():void
         {
              var myVar = new SomeObject(); // in my case, this is a new MC from the library
              myVar.newpageButton_mc.addEventListener(MouseEvent.MOUSE_DOWN, loadANewPage);
              addChild(myVar);
         }
         private function loadANewPage(e:MouseEvent):void
         {
              this.removeChildAt(0); //removes previous page
              var myVar = new SomeObject();
              addChild(myVar); // display the new page
         }
    }
    I am making a 24/7 kiosk app and am noticing that the "pages" I load from the library using the above technique continually increases the memory usage (using Monster Debugger 3 and testing the SWF from within Flash Pro CS5 on a Mac.)

    As I understand it "myVar" are the only references to each "SomeObject" object that gets instantiated. Shouldn't the fact that myVar is local mean that SomeObject should be available for garbage collection after each new page is loaded?

  2. #2
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    The display is also a reference, and the listener may count as one too. You're already removing the item from the display, but try removing the event listener as well.

  3. #3
    Senior Member
    Join Date
    Mar 2003
    Location
    wishconsin
    Posts
    151
    Quote Originally Posted by 5TonsOfFlax View Post
    try removing the event listener as well.
    Thank you for the reply. Looking back at my actual code, I am removing the event listener for the button.

    here's an example that's closer to the actual code i'm using. It's a bit more involved because I want to animate a glow on the button and make a sound before loading a new page (note that I am also using Greensock's TweenLite class). I also want to quickly disable any other buttons on the page so (being a touch screen kiosk) other buttons can't be activated after one is touched (im doing this by simply adding a MovieClip from the library over the top of everything and then removing it after the glow has completed, removing the child and nulling the class variable for it):

    Code:
    public class MyClass extends MovieClip
    {
    
         private var blockEverything_mc:MovieClip;
         // SOUND
         private static var btnSndAsc:Sound = new Sound();
    
         public function MyClass():void
         {
              //constructor
              myMethodThatLoadsAPage();
    
              var req1:URLRequest = new URLRequest("button sound ascending.mp3");
              btnSndAsc.load(req1);
         }
         private function myMethodThatLoadsAPage():void
         {
              var myVar = new SomeObject(); // in my case, this is a new MC from the library
              myVar.newpageButton_mc.f = loadANewPage; // the function that needs to be run after the glow animation
              myVar.newpageButton_mc.addEventListener(MouseEvent.MOUSE_DOWN, buttonGlow);
              addChild(myVar);
         }
         private function loadANewPage():void
         {
              this.removeChildAt(0); //removes previous page
              var myVar = new SomeObject();
              addChild(myVar); // display the new page
         }
         private function buttonGlow(e:MouseEvent):void
    	{
    		blockEverything();
    		
    		btnSndAsc.play();
    		
    		
    		e.target.removeEventListener(MouseEvent.MOUSE_DOWN, buttonGlow); // remove event listener of the button that called this
    		e.target.glow_mc.alpha = 1;
    		
    		// if there's an argument that is needed by the function that ultimately gets run
                    // i want to use a different onComplete function after the glow that sends that arg
    		if (e.target.p != undefined) {
    
    			TweenLite.to(e.target.glow_mc, 0.2, {alpha:0, ease:Linear.easeNone});
    			TweenLite.to(e.target.glow_mc, 0.2, {delay: 0.2, alpha:1, overwrite:false, ease:Linear.easeNone});
    			TweenLite.to(e.target.glow_mc, 0.2, {delay: 0.4, alpha:0, overwrite:false, ease:Linear.easeNone, onComplete:glowCompleteParams});
    			
    		}else{
    			TweenLite.to(e.target.glow_mc, 0.2, {alpha:0, ease:Linear.easeNone});
    			TweenLite.to(e.target.glow_mc, 0.2, {delay: 0.2, alpha:1, overwrite:false, ease:Linear.easeNone});
    			TweenLite.to(e.target.glow_mc, 0.2, {delay: 0.4, alpha:0, overwrite:false, ease:Linear.easeNone, onComplete:glowComplete});
    		}
    		function glowComplete():void
    		{
                            // remove and destroy the "blocker" movieclip
                            // then call the intended function
    			removeChild(blockEverything_mc);
    			blockEverything_mc = null;
    			e.target.f();
    		}
    		function glowCompleteParams():void
    		{
                            // same as above, but with an argument
    			removeChild(blockEverything_mc);
    			blockEverything_mc = null;
    			e.target.f(e.target.p);
    		}
    
    	}
              private function blockEverything():void
    	{
    		blockEverything_mc = new BlockEverything();
    		blockEverything_mc.alpha = 0;
    		addChild(blockEverything_mc);
    	}
    }
    I code in an absolute vacuum, besides these forums So i get the sense that the above methodology could warrant some criticism, which I WELCOME. Thanks.
    Last edited by ingofutz; 07-01-2011 at 02:42 PM.

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I see a few things I'd change. The first and easiest is to use currentTarget rather than target. The difference is that currentTarget is definitely the object which the listener was attached to, whereas target may be a child of that object. If target and currentTarget are different, then your removeEventListener line will not actually remove the event listener because it was never on the object you tried to remove it from.

    Save event.currentTarget in a variable so that you don't have to constantly do the property lookup.

    The second thing is that I would move glowComplete and glowCompleteParams out of buttonGlow. That will mean changing the scope of a few things. You'll need to move the variable you save event.currentTarget out to class scope. And that means you'll want to disable buttonGlow if it's currently already going just to prevent that reference from being overridden. Do not forget to null that variable after glowComplete or glowCompleteParams.

    Do not throw away your BlockEverything instance. Instead of creating a new one each time you call blockEverything, just have one that you create on initialization. Then simply add and remove it from the display.

    I also do not like the removeChildAt here, since it does not carry any semantic connection to what you are trying to accomplish. I'd keep a class level currentPage variable and set that when you add a page. Use that when you remove a page. Set it to null when no page is up.

  5. #5
    Senior Member
    Join Date
    Mar 2003
    Location
    wishconsin
    Posts
    151
    Your suggestions are immensely appreciated! I'll give all of this a try.

  6. #6
    Senior Member
    Join Date
    Mar 2003
    Location
    wishconsin
    Posts
    151
    I must also add an example of what I'm doing in some instances to load a "page".

    Code:
    private function loadANewPage():void
         {
    		this.removeChildAt(0);
    		var mp:MovieClip = new MapPage();
    		mp.addEventListener(Event.ADDED_TO_STAGE, setupMPage);
                    // i use nested functions like the following a lot
                    // in order to avoid using class variables
    		function setupMPage():void
    		{
                            // one of the buttons on this new page is the "close" button
                            // the second arg here tells setupMapControls what function to run when close is touched
    			setupMapControls(mp, myMethodThatLoadsAPage);
    		}
    		
    		this.addChild(mp);		
    	}
    The above may or may not be relevant to my issues, but I thought I'd add it because I do this a lot.

  7. #7
    Senior Member
    Join Date
    Mar 2003
    Location
    wishconsin
    Posts
    151
    Regarding .currentTarget, would using mouseChildren = false; on the button movieclip alleviate this problem?

  8. #8
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Nested functions are kind of a not-generally-well-understood area. You absolutely can use them like you are doing there to avoid having to declare class-scoped variables. But in doing so, you get a NEW setupMPage function every time you execute loadANewPage. And if you are doing something which would cause those functions to stick around (such as using them as event listeners on an object which sticks around) then they can accumulate in memory. Be very careful of all of the closures you create and how they hang on to references. Every local variable in loadANewPage is bound in setupMPage, even if it's not used. That means that the inner scoped function can cause things in the outer scope to stick around longer than they otherwise would.

    Also, setupMPage needs to take an event argument. And it should remove itself as a listener.

    Yes, using mouseChildren = false should prevent children of that instance from dispatching events. In some cases, that may prevent an event from being dispatched at all. I prefer to use currentTarget almost everywhere I get a value from the event in a handler but that's a personal preference.

  9. #9
    Senior Member
    Join Date
    Mar 2003
    Location
    wishconsin
    Posts
    151
    Thank you for the reply and suggestions. They are very helpful!

    Regarding my memory issues... I've discovered that it seems to have something to do with the graphics I imported from Illustrator (?!). Very strange. I first tested this by loading an alternative MC from the library. Monster Debugger ceased to display increasing memory usage. So, I went back to my imported graphic (it was a map) and broke down all of the symbols and text objects. I didn't see any movie clips....I can't imagine Illustrator creating and hiding any code... The only think I can think of is that all of the text fields imported as the "TLF" version of text fields. Could those have been the culprit for some reason?

    Anyway, when I broke everything down to shapes, I no longer seem to have the memory leak. This is very strange.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center