AS3 String Memory Leak

2019-07-07 01:19发布

问题:

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.

回答1:

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.



回答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.



回答3:

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