利用Dictionary的弱引用特性实现动态内存管理

转载http://blog.domlib.com/articles/223.html


这几天看了些文章,提供了一种显示对象位图化并共享位图数据的优化方案,测试了下能提高不少性能,所以想自己也实现一个试试。基本思路如下:

 
  
?
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
28
29
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.utils.Dictionary;
import flash.utils.getQualifiedClassName;
 
public class CachedSprite extends Sprite
{
     protected static var cachedData:Dictionary = new Dictionary;
 
     public var clip:Bitmap;
 
     public function CachedSprite(asset: Object )
     {
         var key = getQualifiedClassName(asset);
         var data:BitmapData = cachedData[key];
         if (data== null )
         {
             var instance:Sprite = new asset();
             data = new BitmapData(instance.width, instance.height, true , 0x0 );
             data.draw(instance, null , null , null , null , true );
             cachedData[key] = data;
         }
 
         clip = new Bitmap(data, "auto" , true );
 
         addChild(clip);
     }
}

    写的过程中,发现了一个老问题。共享的位图数据bitmapData是缓存在类静态变量里的。如果不显式去销毁,就永远无法被回收。而位图数据通常是最消耗内存的,不能忽视。销毁的时机当然就是所有引用这个bitmapData的实例都被回收了之后。但是我们怎么才能知道一个对象被回收了呢?答案是:不能。至少目前FP没有给我们提供内存管理的api,让我们知道什么对象要被回收了。

    不能知道对象实例什么时候被回收,我们只好采用另一种常见方案了:用一个静态变量记录当前的实例数,写一个dispose()方法去显式递减实例数,然后在代码里每个使用完这个实例的地方,都调用一次dispose(),当实例数为0时销毁bitmapData。但是这个方法很容易造成内存泄露的隐患。只要你在一个地方使用完没有调用dispose()就会必然导致内存泄露。这对于大型项目来说是很难避免的。感觉这样就退回到低级语言的开发效率上去了,需要花额外的时间去一个个检查dispose()。

    那就没有能自动管理内存的方案了吗?我想了一晚也没想出来。早上决定放弃的时候,突然发现了新方案:可以用字典类Dictionary的弱引用特性来解决这个问题!弱引用只存在事件监听和Dictionary的key上。而Dictionary的key是可以使用复杂对象的。使用弱引用,相当于告诉FP这个引用计数无效。也就是其他对象还存在对目标对象的引用时,我靠这个弱引用依然可以访问到它。而当其他的引用都断开的时候,它就会在GC时被强制回收,正好巧妙地解决了这个问题!并且因为GC不是立即进行的,其他引用断开后还能缓存一段时间,经过测试,只要GC还没有销毁对象,通过字典类仍然可以访问到缓存的数据,这样也同时解决了需要设置延迟回收时间的问题。浑然天成。

    具体就是在初始化Dictionary时传入一个true,开启key的弱引用。然后把之前的写法调转一下,key和value换一下位置就行了。因为只有key是可以当做若引用的。下面把改过的代码再贴一遍:

 
  
?
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
28
29
30
public class CachedSprite extends Sprite
{
     protected static var cachedData:Dictionary = new Dictionary( true );
 
     public var clip:Bitmap;
 
     public function CachedSprite(asset: Object )
     {
         var data:BitmapData;
         var key = getQualifiedClassName(asset);
         for ( var value:* in cachedData)
         {
             if (cachedData[value]==key)
             {
                 data = value as BitmapData;
             }
         }
         if (data== null )
         {
             var instance:Sprite = new asset();
             data = new BitmapData(instance.width, instance.height, true , 0x0 );
             data.draw(instance, null , null , null , null , true );
             cachedData[data] = key;
         }
 
         clip = new Bitmap(data, "auto" , true );
 
         addChild(clip);
     }
}
[更新]后来全面测试了下:
1.Dictionary的弱引用只对key为引用型对象是有效的,也就是如果用int,String这些基本数据类型作为key,是不存在弱引用的情况的。
2.如果开启了弱引用,并且使用引用型对象作为key,无论value是否是引用型,是否被外部引用,都会回收key,这样会导致key-value的映射关系也会被移除。但是Dictionary[key] = [key]情况除外。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值