AS3字符串内存泄漏

3
我已经在AS3中编程一段时间了,发现一个非常奇怪的问题,字符串没有任何明显原因却一直停留在内存中。下面的程序只是将label.text属性更改为随机字符串,它运行得很好,但当我查看Flex分析器时,我注意到字符串数量在稳步增加,我尝试执行垃圾回收器但没有帮助。
这是一个内存泄漏吗?我该如何解决?
据我所知,这些字符串应该被垃圾回收器收集,因为没有对象引用它们,但并非所有字符串都是这样。
以下是代码和Flex分析器截图显示的String实例数量。
<?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>

抱歉,分数不到10分,这是性能分析器的截图http://imageshack.us/a/img11/9716/stackw.png

已解决

Baris和Loxxy你们是对的,我做了一些更改来隔离问题,它增长到约30Mb,然后垃圾回收器释放一些内存,但它从未回到起始点约2mb的状态,而是一遍又一遍地从约20mb到30mb。

这是用于测试的代码

<?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>

同时调用System.gc()也没有任何作用,可能gc需要一些暂停才能运行。


1
如果您在一个紧密的循环中非常快地生成字符串,可能垃圾回收器没有足够的时间来释放您的字符串。我只是猜测,因为我已经有一段时间没有做AS3工作了。10毫秒似乎并不那么快,但我在AS3中看到过更奇怪的事情。您尝试过慢一点的计时器吗? - xxbbcc
是的,实际上这是一个测试,我遇到了其他不使用计时器的程序也出现了同样的问题,我还尝试通过Flex分析器界面强制垃圾回收。 - Iván Quiñones
或者您可以尝试安装不同的播放器版本 - 我曾经看到Adobe在发布新版本时经常会引入Flash Player的重大错误。您当前的版本可能存在GC错误。您的代码似乎是正确的。 - xxbbcc
我尝试了两台使用不同次要版本的Flash Player的计算机,但结果相同,在Adobe论坛中搜索了它,但没有找到任何信息。期待更改主要版本。 - Iván Quiñones
3个回答

4
垃圾回收器会在任何时候运行。通常它会在分配新对象时运行,但如果内存使用率不高,则可能不会在您的情况下运行。
您可以尝试调用System.gc()以查看其是否释放了这些字符串。但您不应在生产代码中使用它。
有关更多信息,请参见答案。

1
但是你不应该在生产代码中使用它。实际上,你不能这样做,因为它只在调试 Flash 播放器上可用。 - blue112
添加了一个按钮来调用System.gc(),但仍然是相同的行为,我让程序继续运行以使用更多的内存,现在String实例正在使用6mb的总内存的80%。 - Iván Quiñones
是的,6MB根本不算什么,就像我说的,GC会在它觉得需要释放时自动释放。你的代码没有问题,实际上你甚至不需要将字符串置空,因为它是一个局部变量,在函数结束时就会超出作用域。 - Barış Uşaklı
1
此外,在进行性能分析时,请查看内存消耗图表。如果图表线在某个点(如6MB)水平,那么就没有内存泄漏。如果图表线继续上升,那就是内存泄漏。 - Sunil D.

2
你是否曾经编写过一个低于推荐延迟的计时器?new Timer(10); 引用自这里
建议不要使用低于20毫秒的延迟。计时器的频率限制为每秒60帧,这意味着低于16.6毫秒的延迟会导致运行时问题。
正如Baris之前所说,人们在应用程序中遇到大量内存问题时,神奇的gc会解决内存问题。除此之外,你既不需要担心它,也无法手动处理它。

将计时器更改为500毫秒,通过连接更多的随机数字来增加字符串的大小以增加内存使用量,但没有任何区别 :( - Iván Quiñones

1
这可能与主字符串有关,它是Flash运行时利用的一种内存优化方式,以最小化相关字符串数据块的冗余分配。
您可以在博客文章Flash String weirdness中阅读有关其真实世界影响的详细分析。
以下是该帖子的一些亮点,与SO相关。
结果
- 如果从长字符串中取出部分字符串,则会保留长字符串。 - 如果连接超过2个字符串,则将第二个字符串作为主字符串保留。 - 如果循环并将字符串相加,则与上述情况相同,它将从第三个添加开始保留主字符串。 - 循环字符串测试似乎表明每个字符串都可以有一系列父级。 - 这不能被证实,因为我们只能访问“getMasterString()”,它返回链的根。
结论
- 字符串具有“父字符串”。 - XML保留对其父字符串的引用。 - 字符串可能会泄漏内存。 - 控制台图形由于上述原因似乎会泄漏。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接