0

I have a simple countdown timer written in AS3 that builds up CPU use and frame render time progressively over time to the point of frame rate dropping to 2-3 per second over the course of 10 minutes. The timeline has 1 frame and the stage has 4 tlf text areas with instance names HH MM SS and FF. The code updates these text areas each frame based upon a comparison with the current time and an "event time".
I've looked in scout and the offending activity is a "Handling event 'render'" which eats up 95% of the active time

Code shown below

import flash.events.Event;
stop();

// ***Customization Point*** Enter the event date as (Year, Month - 1, day, 24Hr Hours,     Minutes -1, Seconds - 1)
var End:Date = new Date(2013, 9, 15, 12, 0, 0);

var Now:Date;
var HH:Number;
var MM:Number;
var SS:Number;
var FF:Number;
stage.addEventListener(Event.ENTER_FRAME, tick);

function tick(e:Event = null):void
{
Now = new Date();
HH = (End.day > Now.day) ? (End.hours - Now.hours + (24 * (End.day - Now.day))) : (End.hours - Now.hours);
MM = (End.minutes == 0)? 60 - Now.minutes : End.minutes - Now.minutes;
MM = (MM == 60)? 0 : MM;
HH = (MM < 0)? HH - 1 : HH - 1;
MM = (MM < 0)? -1 * MM : MM;

SS = (End.seconds == 0)? 60 - Now.seconds : End.seconds - Now.seconds;
SS = (SS == 60)? 0 : SS;
MM = (SS < 0)? MM - 1 : MM;
SS = (SS < 0)? -1 * SS : SS;

FF = 30 - Math.round(Now.milliseconds / 33.33);

F.text = (FF < 10) ? "0" + FF.toString() : FF.toString();
S.text = (SS < 10) ? "0" + SS.toString() : SS.toString();
M.text = (MM < 10) ? "0" + MM.toString() : MM.toString();
H.text = (HH < 10) ? "0" + HH.toString() : HH.toString();                                           
}
  • yeah dont use enter frame for a timer, use the timer class http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Timer.html – Ronnie Oct 15 '13 at 19:28
  • Same buildup of render time and loss of frame rate with replacing enter_frame with a 33ms Timer Tick – Seth Phillips Oct 15 '13 at 19:54
  • 1
    If possible, I would highly suggest not using TLF TextFields - they are extremely expensive. Use regular dynamic TextFields instead. – Nabren Oct 15 '13 at 20:01
  • interestingly, a second timer that simply goes to a blank frame for one frame and then back again resets the render time almost as if it triggers the garbage collection and resets the animation. There is still a build over time though, and every loop through starts the ramp up of render time a little higher. – Seth Phillips Oct 15 '13 at 20:15
  • If performance drop after few minutes it might be problem with garbage collector or You creating somewhere objects instantly and not release them. Can You check app ram usage or run profiler ? – turbosqel Oct 15 '13 at 20:39
  • what you see is what you get with this one. there is no more code than you see above which is why I'm so surprised that it goes wonky so fast – Seth Phillips Oct 15 '13 at 20:43
  • As @Nabren i would try with regular textfields to see the difference. – mika Oct 15 '13 at 21:51
  • @Nabren, if you'd like the credit for the answer please post it as an answer. Classic text solved it. the TLF text fields must have been stored in memory as they were updated. – Seth Phillips Oct 16 '13 at 15:09

2 Answers2

1

You are adding one enter frame listener per FRAME, these build up and cause lags. Make it so that the listener is added once (use flag for this).

var flag:Boolean; // default is false, but we don't want a value assigned HERE
if (!flag) {
    flag=true;
    stage.addEventListener(Event.ENTER_FRAME, tick);
}

Update: Maybe declaring a variable resets its value, so you can try this instead:

if (!this["flag"]) {
    this["flag"]=true;
    stage.addEventListener(Event.ENTER_FRAME, tick);
}

The change eliminates the local var, and now saves the state on the MovieClip instance, so it persists.

If this won't fix the issue either, try static var flag:Boolean with the first example. (Personally I don't like timeline code, with it you are not in full control of code and data flow, so it can throw up for various Flash engine issues. Also I don't have tools to reproduce this issue, my Flash CS4 trial is long over.)

Vesper
  • 18,599
  • 6
  • 39
  • 61
  • Nope. same result. The timeline stops on the one and only frame so it doesnt loop and fire the beginning code again. The only code that should fire is the function triggered by the event listener. My assumption is that the Now = new Date() somehow stores each "old" date from previous frames in memory and doesnt dispose of it – Seth Phillips Oct 16 '13 at 15:05
  • Weird that it didn't fix, and no, if you have code in the timeline, it is executed on enter fgrame event if the frame with code is current, regardless of MC's playing state. `Date` objects don't create lasting buildup, as they are no longer referenced after this code segment finishes. Try the updated code. – Vesper Oct 17 '13 at 03:08
  • 1
    You're wrong about that, you can easily test it by a simple one frame animation with stop(); and trace("test"); Then wrap the trace("test") inside of a function fired by an enter_frame event listener. It was a good thought though, and it was my first go to as a reason before I added the stop(); command. turns out it was the TLF text fields, changing them to classic fixed it. must be why Adobe took them out of CC – Seth Phillips Oct 17 '13 at 20:36
  • So, TLF text fields have memory leaks? Nice to know. Pity I couldn't help, but let it be. – Vesper Oct 18 '13 at 03:41
1

TLF TextFields are extremely expensive and have significant overhead over regular TextFields.

As a result where possible you should always use regular dynamic TextFields.

Nabren
  • 582
  • 1
  • 7
  • 17