flex 内存回收经典文章(2)

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.

1
2
3
4
5
6
7
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:

1
2
3
4
5
6
7
8
9
10
11
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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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:

1
2
3
4
5
6
7
8
9
10
<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.

Stable Memory Consumption

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.




Full screen slides available here.

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

References

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值