【问题标题】:Memory usage in Flash / Flex / AS3Flash / Flex / AS3 中的内存使用情况
【发布时间】:2025-12-30 14:00:06
【问题描述】:

我在 Flash 应用程序中的内存管理方面遇到了一些问题。内存使用量增长了很多,我已经追踪到我加载资源的方式。

我在一个嵌入式类中嵌入了几个光栅图像,像这样

[Embed(source="/home/gabriel/text_hard.jpg")]
public static var ASSET_text_hard_DOT_jpg : Class;

然后我以这种方式实例化资产

var pClass : Class = Embedded[sResource] as Class;
return new pClass() as Bitmap;

此时,内存使用量上升,这是完全正常的。但是,nulling 对对象的所有引用不会释放内存。

基于这种行为,看起来 Flash 播放器在我第一次请求它时正在创建该类的实例,但从未释放它 - 并非没有引用,调用 System.gc(),执行双重 LocalConnection 技巧,或在 BitmapData 对象上调用 dispose()。

当然,这是非常不可取的 - 内存使用量会增加,直到 SWF 中的所有内容都被实例化,无论我是否很久以前就停止使用某些资产。

我的分析正确吗?有什么办法可以解决这个问题吗?

【问题讨论】:

    标签: apache-flex flash memory-management memory-leaks actionscript-3


    【解决方案1】:

    确保在非调试播放器中再次运行测试。调试播放器在释放资产时并不总是正确回收所有内存。

    此外,由于您使用的是嵌入式而不是加载的资产,实际数据可能永远不会发布。由于它是您的 SWF 的一部分,因此您可以合理地期望它在您的 SWF 的整个生命周期内都在内存中。

    【讨论】:

      【解决方案2】:

      你为什么要使用这个???

      var pClass : Class = Embedded[sResource] as Class; 
      return new pClass() as Bitmap;
      

      有时动态资源分配有问题,无法释放。例如,我之前在使用 flash player 和 flex 时也遇到过类似的问题。加载和卸载相同的外部 swf...内存随着加载的 swf 的大小而不断增加,即使我正在调用 system.gc();卸载 swf 后。

      所以我的建议是跳过这种方法并使用您描述的第一种情况。


      更新 1

      <?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" 
          creationComplete   = "creationComplete()">
      
      <fx:Script>
          <![CDATA[
      
      
      
              [Embed(source="/assets/logo1w.png")]
              private static var asset1:Class;
      
              [Embed(source="/assets/060110sinkhole.jpg")]
              private static var asset2:Class; 
      
      
              private static var _dict:Dictionary = new Dictionary();
      
              private static function initDictionary():void
              {
                  _dict["/assets/logo1w.png"] = asset1;
                  _dict["/assets/060110sinkhole.jpg"] = asset2;
              }
      
              public static function getAssetClass(assetPath:String):Class
              {
                  // if the asset is already in the dictionary then just return it
                  if(_dict[assetPath] !=  null)
                  {
                      return _dict[assetPath] as Class; 
                  }
      
                  return null;
              }
      
              private function creationComplete():void
              {
                  initDictionary();
                  var asset1:Class = getAssetClass("/assets/logo1w.png");
                  var asset2:Class = getAssetClass("/assets/060110sinkhole.jpg");
                  var asset3:Class = getAssetClass("/assets/logo1w.png");
                  var asset4:Class = getAssetClass("/assets/060110sinkhole.jpg");
                  var asset5:Class = getAssetClass("/assets/logo1w.png");
              }
          ]]>
      </fx:Script>
      

      【讨论】:

      • 对不起,我不太明白。我只描述了一种方法。第一个 sn-p 显示我如何嵌入资产,第二个显示我如何实例化它们。你的意思是我为什么不直接做new ASSET_text_hard_DOT_jpg()?那是因为我的代码非常复杂,并不总是事先知道它需要什么,例如它从几个部分创建一个字符串并获取该命名图像(即“text_”+ s_lDifficulty[nDifficulty] ->“text_hard”)跨度>
      • 很抱歉,但我认为您想要实现的目标是不可能的。据我所知,在构建 swf 时会嵌入资源,我不确定您是否可以按照您的描述动态嵌入资源。我会做什么来创建字典并将我需要的所有资源放在那里。我会像现在在响应中编写的 UPDATE1 代码一样使用它。
      【解决方案3】:

      此时,内存使用量上升, 这是完全正常的。然而, 清空所有对 对象不会释放内存。

      这也是完全正常的。很少有任何系统能保证您停止引用代码中的对象的那一刻就是将其内存返回给操作系统的那一刻。这正是存在诸如 System.gc() 之类的方法的原因,它允许您在需要时强制进行清理。通常,为了提高效率,应用程序可能会实施某种池来保留对象和内存(因为内存分配通常很慢)。即使应用程序确实将内存返回给操作系统,操作系统可能仍会暂时认为它已分配给应用程序,以防应用程序需要稍后再请求更多。

      您只需要担心释放的内存没有被重用。例如,您应该发现,如果您创建一个对象、释放它并重复此过程,内存使用量不应随着您创建的对象数量线性增长,因为先前释放的对象的内存会重新分配给新的对象。如果您可以确认没有发生这种情况,请编辑您的问题并这样说。 :)

      【讨论】:

        【解决方案4】:

        事实证明,我保留了对未卸载对象的引用。非常棘手的。 GC 在我描述的所有情况下都能正常工作,但我怀疑可能有所不同。

        更准确地说,加载一个 SWF,实例化其中定义的许多类,将它们添加到显示列表,操作它们,然后删除所有引用并卸载 SWF,这给我留下了几乎与开始时完全相同的内存。

        【讨论】: