Copy link to clipboard
Copied
Hello,
We have a Flex 4/Actionscript 3 application that involves "scrubbing" through a Movie Clip that is a swf file derived from a .mov file. This is accomplished by listenening to the change in value of an HSlider and calling gotoAndStop(n) on the Movie Clip repeatedly as the slider is dragged. The Movie Clip is 720 pixels wide by 405 pixels high.
It works great, however, after doing this scrubbing action a number of times, which is required by our application, we notice the memory (by tracing System.totalMemory and System.privateMemory) increasing dramatically; and when it gets to around 100 MB (though it's not the same every time), the Flash plugin in the browser will crash. Our assumption is that this happens because the scrubbing essentially loads dozens of bitmaps (each frame of the Movie Clip that is scrubbed over) very rapidly.
To try and ameliorate this, we have implemented aggressive garbage collection by calling System.pauseForGCIfCollectionImminent(0.1) on a timer every 10 seconds. This usually keeps Flash from crashing, however, sometimes the garbage collection itself causes Flash to crash, though it's not 100% predictable. We know this because we are tracing the garbage collection action and can see Flash crash when that action occurs.
It doesn't seem like we have a memory leak per se, as the free memory is eventually regained when forcing garbage collection.
So I have a couple of questions:
1) Is there any way to keep the memory from getting so large in the first place, given that we need this scrubbing functionality?
2) If not, is there a better way of tweaking the garbage collection so that it frees up memory while not itself causing Flash to crash?
Copy link to clipboard
Copied
are you sure there's nothing else (like actionscript) on those frames through which you're scrubbing?
Copy link to clipboard
Copied
kglad,
If you mean in the sense of actionscript embedded on a frame in a timeline -- no, there is nothing like that. This is a Flex/AS3/FlashBuilder built app, no timelines or anything.
I'm curious as to why simply playing the Movie Clip does not seem to cause the memory to increase, while the scrubbing action (which calls gotoAndStop on each frame) does cause the memory to increase. It is essentially doing the same thing, loading and unloading a series of bitmaps.
Copy link to clipboard
Copied
copy and paste the code you're using.
Copy link to clipboard
Copied
public function set currentFrame(frameNumber:Number):void {
if(mcMedia){ // mcMedia refers to the MovieClip
if(playing){ // playing is a boolean that returns whether the MovieClip is playing or not
mcMedia.gotoAndPlay(frameNumber);
}else{
mcMedia.gotoAndStop(frameNumber);
}
dispatchEvent(new Event("currentFrameChanged"));
updateCurrentChapter();
}
}
[Bindable (event="currentFrameChanged")]
public function get currentFrame():Number{
if(mcMedia){
return mcMedia.currentFrame;
}
return -1;
}
Copy link to clipboard
Copied
how many frames in your scrubbing swf?
and, there must be more code than that.
Copy link to clipboard
Copied
The swf could have anywhere from 100 to 2500 or more frames. They are animation assignments that are uploaded by students; our application is so a teacher can critique their animation assignments.
There is a lot more code; the scrubbing is just one aspect of a large application, which also includes video streaming with embedded metadata, and a drawing board. However, we have isolated the memory increases to the scrubbing, so I thought I'd just post the code that deals with that aspect specifically.
Here is the code that handles the scrub bar changes. Pretty standard stuff.
private function handleScrubberChange():void{
if(_mediaManager.currentMediaModel){ // currentMediaModel is the object that contains the set currentFrame function
_mediaManager.currentMediaModel.currentFrame = swfScrubber.value;
}
}
Copy link to clipboard
Copied
i can't duplicate that problem using 135 bitmaps and timeline scrubbing.
i see memory increase up to a max when i scrub across all frames but:
1. i can't go above the max no matter how long or how rapidly (or slowly) i scrub
2. i see memory drop dramatically whenever i stop scrubbing.
so, i suspect you're doing something other than displaying many bitmaps when you scrub your timeline.
Copy link to clipboard
Copied
kglad, thanks for keeping the discussion going. Can you let me know the pixel dimensions of the bitmaps that you're scrubbing? Also, does the memory drop dramatically immediately after you stop scrubbing, or does it take a while for the garbage collection to kick in? And what is the max memory in MB you're seeing?
Copy link to clipboard
Copied
the bitmaps vary from 160x160 to 1330x930. to give you an idea of overall size, the swf is just under 7mb and the fla is just under 45mb.
when scrubbiung the memory goes up to a max of about 130mb and then, when scrubbing stops, steady descreases down to 16mb in just under 10 seconds.
when i stop scrubbing, about 2mb (out of16mb) is from bitmaps. when scrubbing, about 106mb (out of 130mb) is from bitmap memory.
Copy link to clipboard
Copied
OK - so you are getting roughly the same results as I am. But that 130 MB doesn't seem to crash the plugin for you? Also, my my memory doesn't decrease nearly as fast as yours. I'm attaching a screenshot that shows the memory trace.
Copy link to clipboard
Copied
i have no player problem. frame rate is a rock solid 60 and doesn't come close to ever going over budget.
btw, i would recommend you use adobe scout to profile your swfs performance.
Copy link to clipboard
Copied
OK, I created a new Flex project with just the simplest possible scrubbing code, plus the memory tracing. Unfortunately, I'm getting the same results as I get in our big app. If I can figure out what you're doing differently, I might be able to get somewhere. Here's the code:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" addedToStage="onAddedToStage()">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.display.Loader;
import flash.system.LoaderContext;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
private var swf:MovieClip;
private var loader:Loader;
private var memoryReportTimer:Timer = new Timer( 15000 );
private var initialMemory:Number;
private var currentMemory:Number;
private function onAddedToStage():void {
var req:URLRequest = new URLRequest( "sampleAsset/AlfredCiminoDemoReel.mov.swf" );
var loaderContext:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain, null);
loader = new Loader();
//loader.dataFormat = URLLoaderDataFormat.BINARY;
swfContainer.addChild( loader );
loader.contentLoaderInfo.addEventListener( Event.COMPLETE, swfLoadComplete );
loader.load( req, loaderContext );
//(loader.content as MovieClip).gotoAndStop(1);
//swf.gotoAndStop(1);
trace( "initial free memory allocation: ", (System.freeMemory / 1024).toFixed(2));
initialMemory = Number((System.totalMemory/1024).toFixed(2));
currentMemory = initialMemory;
memoryReportTimer.addEventListener( TimerEvent.TIMER, reportMemoryDelta );
memoryReportTimer.start();
}
private function swfLoadComplete( e:Event ):void {
trace( "loading complete." );
swf = loader.content as MovieClip;
swf.gotoAndStop(1);
//swfContainer.addChild(swf);
scrubber.maximum = swf.totalFrames;
}
private function reportMemoryDelta( evt:TimerEvent ):void {
var currentMemory_temp:Number = Number((System.totalMemory/1024).toFixed(2));
var tenSecDelta:Number = currentMemory_temp - currentMemory;
currentMemory = currentMemory_temp;
var overallDelta:Number = currentMemory - initialMemory;
trace( "10 second change: ", tenSecDelta, ", overall change: ", overallDelta );
trace( "free memory: ", (System.freeMemory / 1024).toFixed(2));
}
public function setCurrentFrame():void {
swf.gotoAndStop(scrubber.value);
}
]]>
</fx:Script>
<s:VGroup>
<mx:UIComponent id="swfContainer" width="720" height="405">
</mx:UIComponent>
<s:HSlider id="scrubber" change="setCurrentFrame()" width="100%" />
</s:VGroup>
</s:Application>
And here's the tracing output:
Copy link to clipboard
Copied
you're using a scrubber component? that could be a problem.
i'm using:
import flash.events.Event;
stop();
var m:Number;
var b:Number;
var traceF:int = stage.frameRate*2;
var loop:int = 0;
// bitmaps are on frames 2 to totalFrames (this code is on frame 1)
paramsF(0,2,stage.stageWidth,this.totalFrames);
this.addEventListener(Event.ENTER_FRAME,f);
function f(e:Event):void{
this.gotoAndStop(Math.round(m*mouseX+b));
}
function paramsF(x1:Number,y1:Number,x2:Number,y2:Number):void{
m = (y1-y2)/(x1-x2);
b = y1-m*x1;
}
Copy link to clipboard
Copied
OK, this just gets weirder and weirder.
I thought I'd try to use nextFrame() and prevFrame() instead of gotoAndStop to see if that would make a difference. Since the scrubbing changes come in faster than one frame at a time, I had to use a temp variable to store the last scrubbed-to frame, and then loop to make up the difference, but it seemed to work pretty well.
Here's the weird part: nextFrame() performed far better than gotoAndStop - the memory barely increased at all while scrubbing. However, prevFrame() performed far WORSE than gotoAndStop - to the tune of 5X-10X worse. Scrubbing backwards, I was able to get the memory to go up to 600MB scrubbing across a couple hundred frames.
Not sure what the solution is, just documenting my work in case anyone else runs into this issue in the future.
Copy link to clipboard
Copied
OK, I got Adobe Scout up and running. Below is a screenshot of what happens when the memory jumps due to scrubbing. It looks like the biggest jump is in "uncategorized" memory. Not very helpful.
Copy link to clipboard
Copied
do you have any timeline sounds?
if not, test with no scrubber component. or, test scrubbing with the component for a swf with many empty frames.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now