`
a3mao
  • 浏览: 562910 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Flex 内存管理

阅读更多
http://spreadingfunkyness.com/garbage-collection-with-flex-and-adobe-air/

Spreading Funkyness
RIAbilitating the Internet

12 Jan Garbage Collection with Flex and Adobe Air
Posted by Cesare
Categories: actionscript, adobeair, flex, programming
I finally found some spare time to organize the stuff presented at flexcamp and make it a blog post. I “argue” with the Flex profiler almost daily and we had an “intense” relationship the month right before the flexcamp. So I felt a talk about profiling and Garbage Collection (GC) was really fit. Right, it is impossible to decouple profiling from GC. If you want to improve the memory management of your application you have to know how the Flash Player (and Adobe Air) manage memory allocation and deallocation.
Let me start by saying there are many blog posts about issues related to GC and profiling, ranging from documentation, presentations, how-tos, etc. I list them at the bottom.
The present post can be considered useful to beginners and medium experienced people which use Flex almost daily and have the need to optimize memory consumption. After introducing the fundamental concepts I will list a set of lessons learned during the development of Posty and Focused. I will particularly focus on the use of renderers’ caches.

Virtual Machine (VM)
The flash player is based on a virtual machine (to be precise the machines are 2, one for actionscript2 and one for actionscript3). VMs dynamically allocate memory when you create new objects. For example the following line of code creates a new Object.

1
var o:Object = new Object()

At startup the VM reserves some memory and when the code above is executed decides where the object goes in the application memory and how much space it takes. As you create objects the VM might use all the memory allocated at startup and, when needed, requests some more to the operative system. Unless you have a program which nonsensically just creates new objects, there will be some time during the execution when an object becomes “useless”, e.g. it is not needed anymore for the correct execution of the program. You’ll see that it is not easy to “understand” when an object is not needed. For now let’s assume we are able to detect it.
In the Flash VM achitecture you cannot explicitly say “delete it”. Memory usage is managed, that is the VM itself is responsible to check which objects are useless and delete them. Such a mechanism is called Garbage Collection.

Garbage Collection
So what can I do as a programmer? Well, you can ease the task of the garbage collector. Let’s see what we expect to happen with the help of a figure.


At startup the application reserves some memory to be used, say four blocks. When you create a new object the VM allocates it using the first slot. Let’s say that after a while o1 is not needed anymore and you set it to null. When you create a new object, o2, you expect that it takes the place of o1. Sometimes it happens, sometimes it does not. This depends on the garbage collection mechanism, which is a pretty complex procedure we are not describing here (a good article has been written by Grant Skinner).
At this point we already have a lesson learned: “setting an object to null does not necessarily free the memory it was occupying“.

This depends on the way GC has been implemented in flash. GC is triggered by allocation” and not deletion. This means that the GC cycle is run when you say new Object() and not when you set it to null.

Memory Consumption
If you have to do with AS3 and Flex you probably know that you can dynamically add UI elements to the graphical interface via a simple method called addChild(). The opposite method is removeChild(), which removes a display element from the UI. To be more precise, the element is deleted from the view (it is not displayed anymore) but this does not mean it has been garbage collected. Let me introduce you to a simple scenario to show you easy is to put too much trust in the removeChild() method.
Many Flex applications load data from a server and display it dynamically, according to the values returned. Usually the view code is isolated in a component, often referred to as renderer, which is responsible of showing the data loaded from the server. We devise a very simple renderer that is made of two text fields, embedded in a VBox. Data shown are field1 and field2, properties of the object provided as input.

<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
    borderStyle="solid" width="200"
    >
    <mx:Script>
        <![CDATA[
    [Bindable] private var _field1:String;
    [Bindable] private var _field2:String;

    override public function set data(value:Object):void {
_field1 = value.field1;
_field2 = value.field2;
    }
]]>
</mx:Script>

<mx:Text text="{_field1}" />
<mx:Text text="{_field2}" />
</mx:VBox>

Let’s simulate data loading by means of a simple function, which returns an array of objects.


private function getData():Array {
    var a:Array = new Array();

    for (var i:uint = 0; i< 200; i++) {
var o:Object = new Object();
o.field1 = "field "+Math.random().toString();
o.field2 = "field "+Math.random().toString();
a.push(o);
    }
    return a;
}

To render data we use a simple function which creates a renderer, sets its data, and adds it to the VBox.

private function loadData():void {
    vbox.removeAllChildren();
    var array:Array = getData();

    for (var i:int = 0; i < array.length; i++) {
var rend:MyRenderer = new MyRenderer();
rend.data = array[i];
box.addChild(rend);
        i++;
    }
}

Do you see the dangerous statement? Not yet? Let me show you. To simulate a repeated action I add a timer which calls the load function each N seconds.


private function init():void {
    var t:Timer = new Timer(2000);
    t.addEventListener(TimerEvent.TIMER, tick);
    t.start();
}

Now try running the profiler. Do you see an ever growing graph like this?



Congrats! We have found a memory leak! A memory leak happens when the same action is repeated and memory consumption grows instead of being constant. Did you find the dangerous statement? It is when you create the renderer. Why? Because you assume that removeAllChildren() removes renderers from the memory. Wrong! As said above that method only removes renderers from the display tree. In fact, as you can see in the profiler, renderers are still there, consuming memory.

UPDATE: Technically speaking this is not a memory leak, because there is nothing that prevents the garbage collector to clean up memory from renderers. A memory leak happens, in fact, when there is something that is supposed to use the renderer (e.g. a listener) even when you remove it from the display tree. In this example renderers are ‘free” and could be garbage collected. But they are not. So the result is the same of a memory leak, an ever growing memory consumption.



There are many techniques to solve this situation. We will show two: caching renderers and dynamic caching.

Caching
Let’s assume you know in advance how many renderers are needed. One way to solve the memory leak is to create a cache of renderers at startup.


private var cache:Array = new Array();

private function initRenderers():void {
    for (var i:int = 0; i < 200; i++) {
renderers.push(new MyRenderer());
    }
}

We can then modify our loadData method like this:


private function loadData():void {
    container.removeAllChildren();
    var array:Array = getData();

    for (var i:int = 0; i < array.length; i++) {
var rend:MyRenderer = cache[i];
rend.data = array[i];
  container.addChild(rend);
i++;
    }
}

As you can see in the code we don’t create new renderers but we look for one in the cache. There are cases when you don’t know in advance which data are returned from the server and then you don’t know how many rendereres you need. In this case you need a dynamic cache.

Dynamic cache
Dynamic caching is based on an elastic mechanism. You have a place where you can look for a renderer: if there is one in the cache, that is returned, otherwise a new one is created temporarily. Better to see some code.


public class MyRendererCache extends Object {

    private static var cache : ArrayCollection = new ArrayCollection();

public function MyRendererCache() {
    super();
            for ( var x : Number = 0; x < 20; x ++ ) {
cache.addItem( new MyRenderer() );
    }
}

public static function getRenderer() : MyRenderer {
    var renderer : MyRenderer;

    if ( cache.length <= 0 ) {
renderer = new MyRenderer();
    } else {
renderer = cache.removeItemAt( 0 ) as MyRenderer;
    }

    return renderer;
        }

        public static function setRenderer( renderer : MyRenderer ) : void {
    cache.addItem( renderer );
        }
}

In the constructor you populate the cache with the minimu number of renderers, say 20 (lines 7-9). The cache has two static methods, getRenderer and setRenderer. The first is used to obtain a renderer, the second to give it back when done. If you look and lines 15-16 the cache returns a new renderer when the cache is empty. This way the number of renderers in memory can grow beyond the minimum number set in the constructor, but just temporarily, since the GC will delete them when not referenced anymore.
An important issue is related to the setRenderer. When you don’t need a renderer anymore you have to return it back to the cache, otherwise we fall again in a memory leak as explained above. To achieve this we exploit the remove event of the renderer. The remove event is triggerer whenever a UI element is removed from the display list. For example when we call removeAllChildren() such event is triggered for each renderer.
We can modify the renderer like this:


<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
    borderStyle="solid" width="200"
    remove="onRemove()"
    >

    private function onRemove():void {
MyRendererCache.setRenderer(this);
    }
....
</VBox>

If you now run the profiler you will notice that memory grows until a given point and then keeps stable as in the figure below.



Congratulations! You have solved the memory leak!

Suggesting the GC
Besides favoring the job of GC Adobe has allowed programmers to suggest the intervention of the GC. The command is in the flash.system package and it is System.gc(). By documentation this “Forces the garbage collection process” but in my experience it is just a vague suggestion of intervention. It can solve some situation, so it is worth trying it at the beginning, when you need a quick way to save some memory.


Here are the slides of my talk at flexcamp.




Full screen slides available here.

The source code of this post is available under the new BSD license.

References
Garbage Collection and Memory Leaks by Alex Aharui. Somehow outdated but a good introduction.
Tip to force GC via local connection.
GC and Flash player 9. Good article by G. Skinner.
GC and reflections on Adobe Air vs the design of Flash player by Sean Christmann (creator of the Ebay Desktop application).
The downside of developing Adobe Air application via Html/JS. Reflections on the lack of a profiler.
Tips to optimize Air/Flash applications presented by Sean Christmann at Max 2008 Milan
分享到:
评论

相关推荐

    Flex内存管理及相关内容

    ### Flex内存管理及相关内容 #### 一、Flex与ActionScript中的内存管理机制 Flex作为一种用于构建RIA(Rich Internet Applications)的应用框架,其背后的编程语言ActionScript(简称AS)支持垃圾回收(Garbage ...

    FLEX内存释放优化原则

    本文将针对“FLEX内存释放优化原则”进行深入探讨,帮助开发者掌握有效的内存管理技巧。 #### 二、核心优化原则 1. **删除对象前需通知系统** - 在删除对象之前,必须明确地告知系统即将进行的操作。这一步骤对于...

    Flex虚拟机内存管理机制及防止内存泄漏

    在Flex应用开发中,内存管理是一个关键环节,它直接影响到程序的性能和稳定性。本篇文章将深入探讨Flex虚拟机的内存管理机制以及如何预防和处理内存泄漏问题。 内存管理在任何软件开发中都至关重要,尤其是在动态...

    flex 内存泄露管理 内存泄露

    总结来说,避免Flex中的内存泄露需要开发者细心地管理和释放事件监听器、子对象引用、静态变量、CSS样式、UI组件、图片资源以及其他加载的媒体和网络资源。遵循这些最佳实践,可以显著提高Flex应用的性能和稳定性。

    Flex 应用内存泄露的分析与诊断

    Flex 应用内存泄露的分析与诊断主要集中在 Flex 应用程序中由于内存管理不当导致的问题。Flex 使用 ActionScript 语言编写,其运行环境在 FlashPlayer 的 ActionScript Virtual Machine (AVM) 中,该虚拟机包含一个...

    Flex内存泄露总结

    Flex内存泄露总结主要聚焦在Flash Player的垃圾回收机制和内存管理问题上,这对于优化Flex应用程序的性能至关重要。首先,我们要理解垃圾回收的基本原理。在Flash Player中,内存的释放工作由垃圾回收器负责,它是一...

    flex内存泄露(转载)

    #### Flex内存泄露的原因 尽管AVM提供了垃圾收集机制,但Flex应用依然可能遭遇内存泄露问题。主要原因是对象引用关系导致垃圾收集器误判某些对象仍处于活动状态。具体而言: 1. **对象引用不当:** 当某个对象实际...

    Flex内存泄露问题

    以下是一些解决Flex内存泄漏的关键点: 1. **删除无用对象**:确保在不再需要对象时正确地删除它们,避免它们在内存中驻留。这包括删除事件监听器、解除绑定数据等。 2. **事件监听器管理**:事件监听器是常见的...

    使用Timer实现FLEX单击双击分离响应

    而压缩包中的"Flex内存管理及相关内容.pdf"文件,可能会涵盖更深入的Flex内存管理知识,如垃圾回收、对象生命周期、性能优化等方面的内容。这部分知识对于大型Flex应用的开发和维护至关重要,它可以帮助开发者避免...

    flex 性能,查看内存

    Flex应用通常涉及大量的交互和动态数据处理,因此性能优化和内存管理是开发过程中的关键环节。以下是对Flex性能优化和内存查看的深入探讨: 1. **Flex性能优化**: - **代码优化**:减少不必要的计算,避免在循环...

    FLEX内存不足,无法使用设计模式的解决办法

    总结来说,当遇到FLEX内存不足导致无法使用设计模式时,可以尝试更新或替换相关DLL文件,以改善应用的内存管理。此解决方案特别适用于那些拥有大型或复杂Flex项目的开发者,通过提升系统资源的利用效率,使得设计...

    有关flex 内存泄漏memory leak介绍的ppt

    本篇内容将深入探讨Flex中的内存泄漏及其原因,以及Flash Player的内存管理机制。 首先,我们来了解一下什么是内存泄漏(Memory Leak)。内存泄漏是指程序在申请内存后,无法释放已不再使用的内存空间,一次小的...

    Flex性能,内存管理和对象缓存

    ### Flex性能、内存管理和对象缓存 #### 一、引言 在开发基于Flex的应用程序时,提升性能、有效管理内存以及合理利用对象缓存是非常重要的。这些技术可以帮助开发者构建出响应迅速、资源消耗低且具有良好用户体验的...

    flex如何进行内存优化

    ### Flex内存优化技巧详解 在开发Flex应用时,合理的内存管理是提高应用性能的关键因素之一。本文将基于提供的文件信息,深入探讨如何更好地优化Flex内存使用,并通过具体实例阐述如何编写更加高效的Flex代码。 ##...

    Flex 有效的内存回收方法

    1. **垃圾收集(Garbage Collection)**: 垃圾收集是Flex中实现内存管理的主要机制。它自动追踪并释放不再使用的对象所占用的内存。理解如何与垃圾收集器协同工作是减少内存问题的关键。开发者应确保不持有对不再...

    flash关于内存管理与内存管理

    总结来说,理解Flash Player的内存管理和垃圾回收机制对于开发健壮的Flex应用程序至关重要。通过合理管理对象引用,以及熟悉和应用不同的垃圾回收策略,开发者可以有效地防止内存泄露,提高程序性能。在实际开发中,...

    Flex的内存数据做等级符号专题图

    在提供的文件列表中,我们看到`.actionScriptProperties`、`.flexProperties`和`.project`文件,这些都是Flex项目的基本配置文件,用于管理编译设置和项目结构。`.Flex的内存数据做等级符号专题图.doc`可能包含详细...

Global site tag (gtag.js) - Google Analytics