3

I've been programming for some time in AS3 and found a really weird problem with strings that for no apparent reason are hanging on the memory, the program below just changes the label.text property with a random string, it works fine but when i looked at the Flex profiler i noticed that the number of Strings is increasing steadly, i tried executing the garbage collector but didnt helped me.

Is this a memory leak? how can i solve it?

As I know this strings should be collected by the garbage collector because there are no objects referencing them, yet this is not happening for all the strings.

Heres the code and a screenshot of the Flex profiler showing the number of String instances.

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:s="library://ns.adobe.com/flex/spark" 
                   xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="windowedapplication1_creationCompleteHandler(event)">
<s:layout>
    <s:BasicLayout/>
</s:layout>
<fx:Script>
    <![CDATA[
        import mx.events.FlexEvent;

        protected var t:Timer=new Timer(10);

        protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
        {
            t.addEventListener(TimerEvent.TIMER,listener,false,0,true);
            t.start();
        }

        protected function listener(e:Event):void
        {
            var s:String=Math.random()+"-->";
            this.fx(s);
            s=null;
        }

        protected function fx(s:String):void
        {
            this.label.text=s;
        }
    ]]>
</fx:Script>
<fx:Declarations>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Label id="label" y="39" left="10" right="10" text="Label"/>
</s:WindowedApplication>

Sorry, less than 10 points, heres the profilers screenshot http://imageshack.us/a/img11/9716/stackw.png

SOLVED

Baris and Loxxy you were right, i made some changes in order to isolate the problem and it grows up to ~30Mb then the garbage collector frees some memory, it never goes back to ~2mb (starting point) but the graph starts to go from ~20mb to ~30mb over and over.

Heres the code to test this

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:s="library://ns.adobe.com/flex/spark" 
                   xmlns:mx="library://ns.adobe.com/flex/mx" creationComplete="windowedapplication1_creationCompleteHandler(event)">
<s:layout>
    <s:BasicLayout/>
</s:layout>
<fx:Script>
    <![CDATA[
        import mx.events.FlexEvent;
        protected var maxMemoryUsage:Number=0;
        protected var i:Number=0;

        protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
        {
            setTimeout(Fx,20);
        }

        protected function Fx():void
        {
            if(i++%1024==0) 
            {
                var mem:Number=System.totalMemory;
                this.maxMemoryUsage = mem>this.maxMemoryUsage?mem:this.maxMemoryUsage;
                trace(this.maxMemoryUsage + ' / ' + mem);
            }

            var s:String="";
            s+=Math.random().toString()+"qwertyuiu...1024 random chars...iiwqe";
            this.aSimpleString=s;
            setTimeout(Fx,20);
        }
    ]]>
</fx:Script>
<fx:Declarations>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
    <fx:String id="aSimpleString"/>
</fx:Declarations>
</s:WindowedApplication>

Also calling to System.gc() did nothing, maybe the gc expects some pause in order to run.

Iván Quiñones
  • 501
  • 4
  • 12
  • 1
    If you generate strings very, very fast, in a tight loop, it could be that the garbage collector doesn't have enough time to free your strings. I'm just guessing here, it's been a while since I did AS3 work. 10ms doesn't seem all that fast but I've seen stranger things in AS3. Have you tried a slower timer? – xxbbcc Oct 10 '12 at 14:23
  • Yes, actually this is a test im having the same problem with other programs that doesn't use timers, also tried forcing the garbage collector through Flex profiler interface – Iván Quiñones Oct 10 '12 at 14:26
  • Alternatively you can try installing a different player version - I've seen Adobe introduce major bugs into the Flash Player routinely when they released a new version. It's possible that your current version has a GC bug. Your code seems correct. – xxbbcc Oct 10 '12 at 14:31
  • I tried with two computers using different minor versions of flash player, yet the same results, searched for it in adobe forums but found nothing. Looking forward to change the major version – Iván Quiñones Oct 10 '12 at 15:37

3 Answers3

4

The garbage collector is going to run whenever it feels like. Usually it happens on allocation of new objects but it might not happen in your case if the memory usage is not high.

You can try to call System.gc() to see if it frees those strings. But you shouldn't use that in your production code.

See this answer for more info.

Community
  • 1
  • 1
Barış Uşaklı
  • 13,440
  • 7
  • 40
  • 66
  • 1
    But you shouldn't use that in your production code. => Actually you can't, it's only available on a debug flash player. – blue112 Oct 10 '12 at 14:57
  • Added a button to call System.gc(), but still the same behaviour, im letting the program to run in order to use more memory, the String instances are now using 80% of 6mb wich is the totall memory my program is allocating – Iván Quiñones Oct 10 '12 at 15:51
  • Yeah 6mb is nothing, like I said the GC will free stuff when it feels like it. There is nothing wrong in your code, actually you don't even need to null the string as it is a local variable and goes out of scope when the function ends. – Barış Uşaklı Oct 10 '12 at 15:53
  • 1
    Also, look at the memory consumption graph when you are profiling. If the chart line levels off at some point (like 6MB) then there is no memory leak. If the chart line continues to rise, that is a memory leak. – Sunil D. Oct 10 '12 at 18:08
2

Haven't you have written a timer to run below the recommended delay? new Timer(10);

From here

A delay lower than 20 milliseconds is not recommended. Timer frequency is limited to 60 frames per second, meaning a delay lower than 16.6 milliseconds causes runtime problems.

As said by Baris earlier, People run into loads of memory in their apps which is when the magical gc arrives to address memory issues. Other than that, you neither need to worry about it nor can you manually do anything about it.

loxxy
  • 12,990
  • 2
  • 25
  • 56
  • Changed the timer to 500ms, increased the size of the string by concatenating more random numbers to increase memory usage, but no difference :( – Iván Quiñones Oct 10 '12 at 16:02
1

This is probably related to Master Strings, a memory optimization that the Flash runtime utilizes to minimize redundant allocation of related chunks of string data.

You can read a detailed analysis about the real world effects on this blog post Flash String weirdness.

Here are some highlights of that post that are relevant to SO:

Results

  • If you take a partial string from a long string, it will keep the long string.
  • If you join more than 2 strings, it will keep the second string as master string.
  • If you loop through and add strings together, it'll be the same as above, where it'll start keeping a master string from your third addition.
  • The looped string test seem to indicate that each string could have a chain of parents.
  • This can not be conformed because we only have access to 'getMasterString()' which returns the root of the chain.

Conclusion

  • Strings have 'parent strings'
  • XML keeps reference to it's parent string(s)
  • Strings can appear to leak memory
  • Console graphing appear to leak due to above reasons
Mark Fox
  • 8,694
  • 9
  • 53
  • 75