A Flash Developer Resource Site

Results 1 to 10 of 10

Thread: Memory management

  1. #1
    Member
    Join Date
    Jan 2009
    Posts
    30

    Loader - memory problem

    Hi. I use a loader to import an image into flash.

    Code:
    private var _loader:Loader = new Loader();
    I add a listener and start loading.

    Code:
    _loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
    
    _loader.load(new URLRequest("bilder/" + e.sökväg + "STOR.jpg"));
    When it's complete I remove the listener

    Code:
    e.target.removeEventListener(Event.COMPLETE, loaderComplete);
    And I do absolutely nothing with the loaded image, I don't add it to
    the display list or anything. But when I use the unload() method on the loader it doesn't disappear from memory! Even if I set the _loader = null it doesn't free up the memory!

    What the f*** is wrong? Any help would be deeply appreciated!

    I check the System.totalMemory property and it just keeps stacking up if I repeat the process.
    Last edited by TwinPeaksBob; 05-06-2009 at 01:51 PM.

  2. #2
    Ө_ө sleepy mod
    Join Date
    Mar 2003
    Location
    Oregon, USA
    Posts
    2,441
    Unload just clears the reference between the loader and the data - you still need to wait for 2-3 passes of the garbage collector before the memory is reclaimed.

  3. #3
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    It will probably be swept on the next pass, but I always do this to speed it up and make sure...

    if (loader.content && loader.content.bitmapData) {
    loader.content.bitmapData.dispose();
    }
    unload();

    That clears the bitmap's pixels and reduces its size to 0x0 immediately. Useful if you're running a ton of loaded bitmaps and need to clear 'em fast...

  4. #4
    newb of many sorts Ralgoth's Avatar
    Join Date
    Apr 2002
    Posts
    466
    If you have the debug version of flash installed, you can force garbage collection with System.gc()

    It doesn't work for the standard flash player, but it will atleast help you to be sure that your images are indead being collected.

    I haven't tried joshstrike's method, it sounds like a good solution though.
    Search first, asked questions later.

  5. #5
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    Golly, that's cool!
    For years I've been making LocalConnections to force the GC into action...it works for some unknown reason. But that's nice!

  6. #6
    Member
    Join Date
    Jan 2009
    Posts
    30
    Quote Originally Posted by joshstrike View Post
    It will probably be swept on the next pass, but I always do this to speed it up and make sure...

    if (loader.content && loader.content.bitmapData) {
    loader.content.bitmapData.dispose();
    }
    unload();

    That clears the bitmap's pixels and reduces its size to 0x0 immediately. Useful if you're running a ton of loaded bitmaps and need to clear 'em fast...
    Alright, thanks!

  7. #7
    Member
    Join Date
    Jan 2009
    Posts
    30
    I'm still not getting it to work though, gah this is driving me insane! Please help!

    I've created this code to try it out, but totalMemory just keeps stacking up!

    stage.addEventListener(Event.ENTER_FRAME, kolla);
    stage.addEventListener(MouseEvent.CLICK, add);
    stage.addEventListener(KeyboardEvent.KEY_DOWN, reportKeyDown);
    var objekt:Loader;
    var bildArray:Array = new Array();
    var bildIndex:uint = new uint();

    function kolla(e:Event):void
    {
    trace(System.totalMemory);
    }

    function add(e:MouseEvent):void
    {
    objekt = new Loader();
    bildArray[bildIndex] = objekt;
    //objekt.contentLoaderInfo.addEventListener(Event.CO MPLETE, loadComplete);
    objekt.load(new URLRequest("DubaiSTOR.jpg"));
    bildIndex++;
    }

    function reportKeyDown(e:KeyboardEvent):void
    {
    if (bildIndex > 0) {
    bildArray[bildIndex - 1].content.bitmapData.dispose();
    bildArray[bildIndex - 1].unload();
    bildArray[bildIndex - 1] = null;
    bildIndex--;
    }
    trace(System.totalMemory + "SCHANSE");
    try {
    new LocalConnection().connect('foo');
    new LocalConnection().connect('foo');
    } catch (e:*) {}
    }
    Last edited by TwinPeaksBob; 05-07-2009 at 10:49 AM.

  8. #8
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    GC is funny. It doesn't happen in the IDE like it does in a browser. You're never going to see it operate properly by tracing out totalMemory. You need to monitor usage from within a browser, over time, and note too that it isn't immediate.
    I use a great tool called ActiveGraph for finding as3 memory leaks while testing in a browser. It isn't available at the author's site anymore so I'm going to post the whole class here. See if this helps.

    just include it, instantiate it, and add it to the stage.

    Code:
    /**
     * ActiveGraph 1.4: an overthought shot in the dark
     * by Jeremy Sachs June 2, 2007
     *
     * I have no blog, yet. When I have one, visit it. 
     * Maybe by then I'll have a new ActiveGraph.
     *
     * You may distribute this class freely, provided it is not modified in any way (including
     * removing this header or changing the package path).
     *
     * [email protected]
     */
    
    
    /* parameters of ActiveGraph (all are optional):
     * interval- the length of time (in milliseconds) between memory checks.
     * (NOTE: a memory check does not always make a point on the graph, only when there's relevant data.)
     * verbose- when set to true, this traces data to your Output menu.
     * visible- when set to false, this keeps Activegraph from drawing to the screen.
     * degree- sets the number of sawtooth patterns to compensate for. (Default is 2)
     */
    
    
    package Active
    {
    	// import statements
    	import flash.display.Sprite;
    	import flash.display.Shape;
    	import flash.text.TextField;
    	import flash.text.TextFormat;
    	import flash.text.TextFieldAutoSize;
    	import flash.utils.Timer;
    	import flash.events.TimerEvent;
    	import flash.events.MouseEvent;
    	import flash.events.Event;
    	import flash.system.System;
    	/**
    	 * ActiveGraph class
    	 * Graphs and displays or outputs memory usage,
    	 * measured in pages- 4-kilobyte chunks
    	 */
    	public class ActiveGraph extends Sprite
    	{
    		private const WIDTH:Number = 50, HEIGHT:Number = 15;
    		private const MEGABYTES:Number = 1/1048576, PAGE:Number = 4096;
    		private var verboseMode:Boolean, returnVal:Boolean;
    		private var lastPlot1:int, lastPlot2:int, plot:int, plotLength:int;
    		private var high:Number, low:Number, itr:Number;
    		private var history:Array;
    		private var output:String, sign:String;
    		private var timer:Timer;
    		// display-related properties
    		private var textBox:TextField;
    		private var textFormat:TextFormat;
    		private var graphBackground:Sprite;
    		private var plotLine:Shape;
    		private var backX:Number, backY:Number;
    		private var numerator:Number, denominator:Number, average:int, old:int;
    		private var caught2:Boolean = false;
    		private var fn:Function;
    		public function ActiveGraph(interval:Number=0, verbose:Boolean=false, drawData:Boolean=true, degree:int=2):void
    		{
    			degree = Math.min(degree, 2);
    			lastPlot1 = lastPlot2 = plot = plotLength = 0;
    			history = new Array();
    			numerator = denominator = average = 0;
    			timer = new Timer(interval);
    			verboseMode = verbose;
    			switch (degree) {
    				case 0 :
    					fn = test0;
    					break;
    				case 2 :
    					fn = test2;
    					break;
    				default :
    					fn = test1;
    					break;
    			}
    			if (drawData) {
    				// instantiate drawing objects
    				textBox = new TextField();
    				textFormat = new TextFormat();
    				graphBackground = new Sprite();
    				plotLine = new Shape();
    				// format textBox
    				textFormat.size = 9;
    				textFormat.font = "Monaco";
    				textFormat.color = 0xFFFFFF;
    				textBox.selectable = false;
    				textBox.autoSize = TextFieldAutoSize.LEFT;
    				textBox.x = WIDTH + 5;
    				textBox.height = HEIGHT;
    				// draw graphBackground
    				graphBackground.graphics.beginFill(0);
    				graphBackground.graphics.drawRect(0,0,WIDTH + 85,HEIGHT);
    				graphBackground.graphics.endFill();
    
    				graphBackground.graphics.lineStyle(0.5,0xFFFFFF);
    				graphBackground.graphics.drawRect(0,0,WIDTH,HEIGHT-1);
    				// add to display list
    				this.addChild(graphBackground);
    				this.addChild(plotLine);
    				this.addChild(textBox);
    
    				timer.addEventListener(TimerEvent.TIMER, drawMem, false, 0, true);
    
    				// implements clicking and dragging behavior
    				textBox.mouseEnabled = false;
    				backX = x, backY = y;
    				graphBackground.addEventListener(MouseEvent.MOUSE_DOWN, handleDrag, false, 0, true);
    				graphBackground.addEventListener(MouseEvent.MOUSE_UP, handleDrag, false, 0, true);
    				this.addEventListener(Event.ADDED_TO_STAGE, loadDrag, false, 0, true);
    			} else {
    				trace("ActiveGraph Running.");
    				timer.addEventListener(TimerEvent.TIMER, trackMem, false, 0, true);
    			}
    			timer.start();
    		}
    		// trackMem- determines whether the GC has run, outputs active memory
    		private function trackMem(e:TimerEvent = null):Boolean
    		{
    			returnVal = false;
    			plot = System.totalMemory/PAGE;
    			old = average;
    			numerator += plot;
    			denominator++;
    			average = numerator/denominator;
    			// if the plot is relevant...
    			if (fn() && verboseMode) {
    				trace(plot);
    			}
    			return returnVal;
    
    		}
    		// test0: doesn't clean up sawteeth
    		private function test0():Boolean
    		{
    			if (lastPlot1 != plot) {
    				returnVal = true;
    				lastPlot1 = plot;
    			}
    			return returnVal;
    		}
    		// test1: cleans up DRC sawteeth
    		private function test1():Boolean
    		{
    			returnVal = (!lastPlot1 || lastPlot1 > plot);
    			lastPlot1 = plot;
    			return returnVal;
    		}
    		// test2: cleans up mark'n'sweep sawteeth
    		private function test2():Boolean
    		{
    			if (lastPlot1 > plot || !lastPlot1) {
    				if (lastPlot2 > plot || !lastPlot2) {
    					caught2 = true;
    				}
    				lastPlot2 = plot;
    			} else if (lastPlot1 < plot && caught2) {
    				plot = lastPlot2;
    				returnVal = true;
    				caught2 = false;
    			}
    			lastPlot1 = plot;
    
    			return returnVal;
    		}
    		// drawMem- updates graph and textbox
    		private function drawMem(e:TimerEvent = null):void
    		{
    			if (trackMem()) {
    				plotLine.graphics.clear();
    				// history array never exceeds a certain length
    				if (plotLength == 21) {
    					history.shift();
    					plotLength--;
    				}
    				// determines whether to display +/- for memory increase/decrease
    				if (plot > history[int(plotLength-1)]) {
    					sign = "+ , ";
    				} else if (plot < history[int(plotLength-1)]) {
    					sign = "- , ";
    				} else {
    					sign = "  , ";
    				}
    				// add plot to data set
    				history.push(plot);
    				plotLength = history.length;
    				// If the graph's long enough,
    				if (plotLength > 1) {
    					plotLine.graphics.lineStyle(2.5,0xFF0000);
    					high = 0, low = Infinity;
    					// find the top and bottom extrema,
    					for (itr = 0; itr < plotLength; itr++) {
    						high = Math.max(history[itr], high);
    						low = Math.min(history[itr], low);
    					}
    					// then plot the graph.
    					plotLine.graphics.moveTo(0, HEIGHT*(1-(history[0]-low)/(high-low)));
    					for (itr = 1; itr < plotLength; itr++) {
    						// I hate the math. I hate writing it out.
    						plotLine.graphics.lineTo(WIDTH*itr/(plotLength-1), 
    						HEIGHT*(1-(history[itr]-low)/(high-low)));
    					}
    				}
    				// put output text in textBox
    				output = plot+sign;
    				textBox.text = String(output)+String(average);
    				textBox.setTextFormat(textFormat);
    			}
    		}
    		private function handleDrag(e:Event):void
    		{
    			// based on the event type,
    			switch (e.type) {
    				case MouseEvent.MOUSE_DOWN :
    					// start dragging,
    					backX = x, backY = y;
    					startDrag();
    					break;
    				case MouseEvent.MOUSE_UP :
    					// stop dragging,
    					stopDrag();
    					break;
    				case Event.MOUSE_LEAVE :
    					// or reset the positiong, in case it's been dragged off the Stage
    					stopDrag();
    					x = backX, y = backY;
    					break;
    			}
    		}
    		private function loadDrag(e:Event):void
    		{
    			this.stage.addEventListener(Event.MOUSE_LEAVE, handleDrag, false, 0, true);
    		}
    		public function get data():Number
    		{
    			return plot;
    		}
    	}
    }

  9. #9
    Member
    Join Date
    Jan 2009
    Posts
    30
    Quote Originally Posted by joshstrike View Post
    Hey dude thanks! You were right, System.totalMemory can't be trusted

    I used ActiveGraph as well as the Activity Control and saw that the memory actually gets freed!

    So thanks

  10. #10
    Senior Member calmchess's Avatar
    Join Date
    Sep 2006
    Location
    Earth
    Posts
    2,588
    Is the graph only a small box in the upper left hand corner of the swf....doesn't seem like much of a graph to me.
    ~calmchess~

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