1. 被删除对象在外部的所有引用一定要被删除干净才能被系统当成垃圾回收处理掉;
2. 父对象内部的子对象被外部其他对象引用了,会导致此子对象不会被删除,子对象不会被删除又会导致了父对象不会被删除;
3. 如果一个对象中引用了外部对象,当自己被删除或者不需要使用此引用对象时,一定要记得把此对象的引用设置为null;
4. 本对象删除不了的原因不一定是自己被引用了,也有可能是自己的孩子被外部引用了,孩子删不掉导致父亲也删不掉;
5. 除了引用需要删除外,系统组件或者全局工具、管理类如果提供了卸载方法的就一定要调用删除内部对象,否则有可能会造成内存泄露和性能损失;
6. 父对象立刻被删除了不代表子对象就会被删除或立刻被删除,可能会在后期被系统自动删除或第二次移除操作时被删除;
7. 如果父对象remove了子对象后没有清除对子对象的引用,子对象一样是不能被删除的,父对象也不能被删除;
8. 注册的事件如果没有被移除不影响自定义的强行回收机制,但有可能会影响正常的回收机制,所以最好是做到注册的事件监听器都要记得移除干净。
9. 父对象被删除了不代表其余子对象都删除了,找到一种状态的泄露代码不等于其他状态就没有泄露了,要各模块各状态逐个进行测试分析,直到测试任何状态下都能删除整个对象为止。
内存泄露举例:
1. 引用泄露:对子对象的引用,外部对本对象或子对象的引用都需要置null;
2. 系统类泄露:使用了系统类而忘记做删除操作了,如BindingUtils.bindSetter(),ChangeWatcher.watch()函数时候完毕后需要调用ChangeWatcher.unwatch()函数来清除引用 ,否则使用此函数的对象将不会被删除; 类似的还有MUSIC,VIDEO,IMAGE,TIMER,EVENT,BINDING等。
3. 效果泄露:当对组件应用效果Effect的时候,当本对象本删除时需要把本对象和子对象上的Effect动画停止掉,然后把Effect的target对象置null; 如果不停止掉动画直接把 Effect置null将不能正常移除对象。
4. SWF泄露:要完全删除一个SWF要调用它的unload()方法并且把对象置null;
5. 图片泄露:当Image对象使用完毕后要把source置null;(为测试);
6. 声音、视频泄露: 当不需要一个音乐或视频是需要停止音乐,删除对象,引用置null;
内存泄露解决方法:
1. 在组件的REMOVED_FROM_STAGE事件回掉中做垃圾处理操作(移除所有对外引用(不管是VO还是组件的都需要删除),删除监听器,调用系统类的清除方法) 先remove再置null, 确保被remove或者removeAll后的对象在外部的引用全部释放干净;
2. 利用Flex的性能优化工具Profile来对项目进程进行监控,可知道历史创建过哪些对象,目前有哪些对象没有被删除,创建的数量,占用的内存比例和用量,创建过程等信息;
总结:关键还是要做好清除工作,自己设置的引用自己要记得删除,自己用过的系统类要记得做好回收处理工作。 以上问题解决的好的话不需要自定义强制回收器也有可能被系统正常的自动回收掉。
补:
内存回收机制测试:
通过编写测试程序发现以下规律,flash内存回收机制的一些特点:
1. 自动内存回收时间不确定。
2. 当一个对象存在被其他对象引用时,这个对象不会被内存回收。
3. 当一个流对象被加载,这个被加载的对象及已经占用了内存。
4. 当一个可视化对象被声明,但 没有添加到画面是占用部分内存,加到displayObject上后,占用全部该对象对象全部内存。
5. 当加载重复对象,例如 加载100个同样的 XX.swf ,如果仅是加载,完成后没有引用,那么内存变化规律,波浪型的。如果某个时间内存回收。那么最后留在内存中的应该是大小近似于加载1个 XX.swf (比1个XX.swf 要大些),从此可以推理出,要是不同的东西被加载,那么最后即便是没有内存漏洞,在一定条件下常用的东西内存中可能也会至少保存每一个不同的东西。经我测试好像是这样的。(测多了可能还会有新发现呢)
6. 引用的包括
1) 对对象的存储: 例如 使用一个数组保存 某些对象,那么数组不释放,对象不可能释放
2) 对事件的监听: 例如 监听过程实际上是使用一个对象保存关键字和关键字关联的事件,对事件关键字,查找然后找出对应的关联function。以下是as2代码。As3 的EventDispatcher功能类似
var btnListener:Object = new Object();
btnListener.click = function() {
trace("haha")
};
bt1.addEventListener("click", btnListener);
使用removerEventer 方法定是要清除掉 处理关键字索引和function 的对象。这样即清除掉了计数引用。
3) 强制回收方式,自动内存回收时间不确定,使用特殊的方法,该方法实际上触发一个错误引起资源回收,使无用的不被计数器引用的都要被回收。(暂时不被使用的,没有引用的那个被自动回收保留的那个一个回收掉)
方法:
try {
trace("force a GC");
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
} catch (e:Error) {
trace(e.message);
}
}
一个例子 假如 有个loader 请求加载url=xxxx.swf 的地址,然后成功加载 xxxx.swf, 10次 ,每次成功后没有处理,假设这时候自动回收没有调用,那么使用强制回收,在debug模式下,会看到回收资源。
[Unload SWF] xxxx.swf ,10个这样的输出。
7. 编写代码注意:
1) 无用的对象,没有引用
2) 降低类设计之间的耦合度,注意对象传递引用的设计等
3) 单例模式,在合适的时候使用
4) 事件循环嵌套造成多次执行,或事件触发循环bug。
5) 对象重复加同样的监听
根据内存特性制作了资源管理类模块
monitor XML 文件
1.客户端根据主配置文件加载 相关模块配置文件,其中之一模块就是monitor xml文件
在编译发布客户端时,可以不包括此文件,在开发人员使用时可以包括此文件,监视客
户端运行情况,那么这样有助于使用更少的类,节省资源。
依赖于XML配置体系的修改,打算客户端重构后实现。
Resource Monitor 资源监视类
资源监视,主要利用弱引用,监视对象是否存在,对象加载的资源大小可以获得,同过对象
是否存在来统计该所有对象资源大小总和。
统计过程中需要对资源类型划分,这里涉及到类型如何划分,以及改造过程中如何传递这
些资源的类型。因为具体改造就是通过一个公用函数获取资源,那么就需要告诉这个函数,
什么地方(模块)用,以便统计。
工作量分布 1编写Resource Monitor类,2修改代码中所有资源加载处。
有一点需要注意,这次添加Resource Monitor类的方式,在以后重构后,加载调用的函数方
式可能都需要改变,设想通过服务来获取资源。那么这个服务的名称等信息自然会得到。
使用方法
weeklyLoader = new Loader();//程序中的loader加载 ,不需要改变
RF.load(weeklyLoader,path,"人物图片");//添加 RF 为资源管理类,采用静态方法访问,path 是资源的url,”人物图片”是模块或资源类型的名称。不需要传递回调方法。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/cui55/archive/2008/03/31/2232705.aspx