关于AS3的垃圾回收
FlashPlayer运行GC(Gabage Collection)的时间并不固定,它会根据你的内存的占用情况来决定运行GC的时间。它会根据用户机器的内存值来设定一个阀值,然后将程序的占用内存量保存在该阀值左右。
GC是在每次申请内存时,根据当前内存占用来触发的。申请内存是一个必要因素。所以,如果一直不进行申请内存的操作,就算内存达到了一个高值,它也不会进行GC。
但要注意,这只是决定回收的时机,而不是回收的内容。这个延迟执行内存回收也就是个表面的现象,不管什么时候执行GC,能够回收的内存最终都能回收,不能回收的肯定不能回收。唯一的影响是,因为回收是延迟执行的,你在查看内存的时候不能直观地看到因为一个对象被废弃而回收内存的过程,会产生迷惑。这对于解决内存泄露是无关紧要的。
内存泄露指的就是当你销毁了一个对象的时候,它占用的内存却无法被回收,这会导致可用内存越来越小最终溢出,在内存紧张的环境中将会造成系统崩溃。
在debug版本下可使用
System.gc()
来强制回收内存,但是在release版本并不起作用。可以使用如下代码
try {
import flash.net.LocalConnection;
var conn1:LocalConnection = new LocalConnection ();
var conn2:LocalConnection = new LocalConnection ();
conn1.connect("gc");
conn2.connect("gc");
}catch(e:Error){}
调用 GC 仅仅是用于测试,实际产品中调用 GC 基本没有意义(除了用于控制 GC时机),如果程序中出现了内存泄露,和 GC 并没有关系。
静态属性是一个特殊的情况。静态属性本身就是根,所以你必须将其设置 null 才有可能被回收,没有别的办法。
弱引用会改变垃圾回收的规则。如果使用了弱引用,addEventListener 将不会影响对象回收,即使对 stage
添加监听,也不会导致自己被回收。
• 一处是 addEventListener 的第5个属性,名为 userWeakReference,设置为true,监听事件将不会影响对象回收。
• 一处是 Dictionary 的构造函数参数,名为 weakKeys,设置为 true,当键为复杂对象时,即使Dictionary 存在,键依然可以被回收。注意,这里说的是键,不是值,值是不享受弱引用待遇的。这个属性也写得也很明白,是weakKeys。
Flash Player的garbage collection(GC)分两种运行方式,一种是“引用计数法”(Reference Counting),一种是“标记-清除法”(Mark Sweeping)。
引用计数法是通过计算指向某个对象的引用的数量来确定是否清除该对象。如果一个对象的引用数量为0,表示程序无法再访问到该对象,则清除该对象;如果引用计数不为0,则不清除。这种方法运行代价较小,但是这种方法无法清除存在循环引用关系的对象集合。标记-清除法是从程序的根对象开始,遍历每个引用指向的对象。遍历经过的对象,则将其标记。最后清除所有没有打上标记的对象。这种方法比较彻底,但是运行代价较高。
FlashPlayer运行GC的时间并不固定,它会根据你的内存的占用情况来决定运行GC的时间。它会根据用户机器的内存值来设定一个阀值,然后将程序的占用内存量保存在该阀值左右。
正因为FlashPlayer这种“不确定”的GC机制,所以我们所要做的主要工作是确保创建的对象在不需要的时候可以被释放。确保对象可以被释放的大原则是没有外部引用指向该对象,除了一般情况下的没有将外部引用显示地设为null之外,以下的情况也会导致对象无法释放:
- 没有remove监听的事件。比如,A对象对某个事件进行监听,监听函数(Event Handler)存在于B对象中,则相当于A对象会保存一个B对象的方法的引用,会导致B对象的内存无法释放。
解决方法:注意remove掉监听事件;或者在调用addEventListener()时,将监听函数设为弱引用,但这种做法只适合一次性的监听。
- 使用BindingUtils.bindSetter()、ChangeWatcher.watch()绑定某个对象之后,没有清除该绑定。道理同1,其实绑定某个对象,也就是监听其发出的PropertyChange事件。
解决方法:使用ChangeWatcher.unwatch()来清除绑定关系。
- 声明了样式,并在样式中使用了嵌入式资源。比如在标签中定义了样式名称。一个对象定义了样式,相当于对外声明了一个全局可用的样式,因此会到导致外部保存了该对象的引用,可能导致对象无法释放。
解决方法:解决方法很多,可以使用动态加载的样式,或者使用一个类或模块(Module)专门管理样式,这些解决方法取决程序的架构设计。
- 使用ExternalInface.callBack()声明了对外的API函数。类似于情况1,一个对象对外声明了API,就使外部保存了指向该对象的引用。
解决方法:如果之前使用了ExternalInface.callBack("APIName", functionName)声明了一个API,则可以使用ExternalInface.callBack("APIName", null)取消该API。
- 某些控件(类似TextInput),或者由这类控件构成的自定义组件,当焦点在这些控件上时,即使从DisplayList移除掉这些控件并删除引用,这些控件对象也无法释放。这个问题还有人提出来是一个Bug(http://bugs.adobe.com/jira/browse/SDK-14781)。这个问题估计和flash的焦点管理机制有关。
解决方法:目前的解决方法只能是等焦点重新转移到其他控件上(比如点击了其他控件),如此之前的控件对象就可以被GC释放。
那应该在什么时候做好垃圾清理的准备工作呢?之前有的文章说应该监听组件的removeFromStage事件,在其处理方法中进行垃圾清理的准备工作(清除引用,删除监听器,清除绑定关系,取消对外API等工作)。
其实这种方法不太确切。因为removedFromStage事件是当组件从DisplayList上移除的时候发出的,并不代表该组件对象的生命周期已经终结。只要程序保留了该组件对象的引用,可以再重新把该组件对象添加到DisplayList上(此时,该组件对象会发出addedToStage事件)。如果单纯在removedFromStage事件的监听函数中做该对象的垃圾清理准备工作,当组件重新被使用的时候,可能导致该组件对象原来的状态被破坏而无法使用。
因此,比较好的实践方法应该是,利用addedToStage、removedFromStage两个事件的对应关系,在removedFromStage事件的处理方法中执行垃圾清理的准备工作(清除引用,删除监听器,清除绑定关系,取消对外API等作),而在addedToStage事件的处理方法中执行removedFromStage事件的处理方法的反操作(设置引用、添加监听、设定绑定关系、设置API...也可以认为是一个组件对象的初始化操作),这样就可以保证一个组件对象被从DisplayList上移除后,可以释放相应内存;如果保存其引用,并将其重新添加到DisplayList上,又可重新使用。
最后翻译一段关于内存清理的建议:
- usage of instance members instead of static members can easily be detected with the profiler (replace by static members where possible)
使用实例成员(instance members),而不是用静态成员(static members),可以更容易地被profiler检查到。因此,尽可能地使用实例成员,而不要用静态成员。
- usage of weak references and / or removal of eventListeners after consumption of the event (if posible) helps reducing the memory usage
在事件完成之后,将其设为引用 而且/或者(and / or) 将其remove掉,有助于减少内存使用。
- moduleLoader.unloadModule leaks memory, use moduleLoader.url=null instead
moduleLoader.unloadModule()会导致内存泄露,因此建议使用将moduleLoader.url=null.
- module memory is freed at arbitrary times (not at unload)
module内存的释放时间是不确定(并不是在unload的时候)。
- runnning debug version of modules leaks huge amounts of memory no matter which container is used
使用debug版本的module会导致大量的内存泄露,不管其容器是否使用。
- declaring modules as modules in the configuration of a flex builder 3 project (and not as applications like in FlexBuilder 2) and optimizing for a specific application reduces module size drastically
将一个程序块声明为module,而不要将其声明为application,并且设置各module专门为一个application进行优化,能大量节约内存。
- forcing garbageCollection (double LocalConnection.connect hack) is necessary in order to measure leaks and to keep memory under control 在适当的时候,为了内存可控,可强制使用垃圾收集器(garbageCollection),方法如下:
try {
import flash.net.LocalConnection;
var conn1:LocalConnection = new LocalConnection ();
var conn2:LocalConnection = new LocalConnection ();
conn1.connect("gc");
conn2.connect("gc");
}catch(e:Error){} - 使用release版的module swf。use the release version of the module swf
- uninstall the debug flash player ("uninstall_flash_player.exe")
卸载debug版的flash player。
- install the release version of the flash player ("install_flash_player_active_x.msi")
安装release版的flash player。
关于AS3的垃圾回收的更多相关文章
- [转]AS3的垃圾回收
GC和内存泄露无关 垃圾回收,这次是一个被无数人讨论过的传统话题. Action Script使用的是和Java相似的内存管理机制,并不会即时回收废弃对象的内存,而是在特定时间统一执行一次GC(Gab ...
- AS3垃圾回收整理
AS3垃圾回收整理 转自 http://bbs.wefdc.com/thread-2366-1-1.html 来源页面: http://www.adobe.com/devnet/actionscrip ...
- as3垃圾回收机制
as3垃圾回收机制 垃圾回收机制详解 能力越大责任越大,这对actionscript3.0来说一点没错.引入这些新控件带来一个副作用:垃圾收集器不再支持自动为你收集 垃圾等假设.也就是说Flash开发 ...
- 白话说java gc垃圾回收
gc是java区别于其他好几门语言(c/c++)的一个代表功能(当然也有很多可以自动管理内存的语言,如所有的脚本语言,你根本不知道内存管理这回事)! 当然,之所以要把c/c++和java相比,是因为j ...
- flex 强制垃圾回收
java和flash的垃圾回收都是一个比较热门的话题,今天我也用一个例子来测试下flash的强制垃圾回收.主要用到的而一个类是LocalConnection. 在Flash player的debug版 ...
- flex 垃圾回收
原文在这里:Garbage Collection with Flex and Adobe Air 我终于有时间来整理在flexcamp上演讲的东西并写篇博客了.就在flexcamp前一个月,我几乎天天 ...
- Javascript 的执行环境(execution context)和作用域(scope)及垃圾回收
执行环境有全局执行环境和函数执行环境之分,每次进入一个新执行环境,都会创建一个搜索变量和函数的作用域链.函数的局部环境不仅有权访问函数作用于中的变量,而且可以访问其外部环境,直到全局环境.全局执行环境 ...
- 修改session垃圾回收几率
<?php //修改session垃圾回收几率 ini_set('session.gc_probability','1'); ini_set('session.gc_divisor','2'); ...
- .NET面试题系列[5] - 垃圾回收:概念与策略
面试出现频率:经常出现,但通常不会问的十分深入.通常来说,看完我这篇文章就足够应付面试了.面试时主要考察垃圾回收的基本概念,标记-压缩算法,以及对于微软的垃圾回收模板的理解.知道什么时候需要继承IDi ...
随机推荐
- 11、WebView 使用总结
<WebView android:id="@+id/webview" android:background="@color/white" android: ...
- 关于javascript模式一书中var white = new Array(256).join(“ ”)
直接进入正题 var white = new Array(256).join(" ") 运行后,我们会发现white.length的长度是255,这个是为什么呢?书上没有给出解答, ...
- python学习之random模块
Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 < ...
- Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)
[题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...
- Linux下gcc和g++编译helloworld
linux C(hello world) 1.使用vi/vim进行编写代码并保存为hello_world.c.如下: 1 2 3 4 5 6 /* This is my first C program ...
- storm,hbase和storm-kafka-0.8-plus兼容性问题
1 org.slf4j.impl.StaticLoggerBinder.SINGLETON错误 方案: 确保slf4j-api-1.5.6.jar 和slf4j-log4j12-1.5.6.jar ...
- hadoop2.7【单节点】单机、伪分布、分布式安装指导
问题导读 1.从本文部署实际部署,总结本地模式.伪分布.分布式的区别是什么?2.单机是否是伪分布?3.本地模式是否可以运行mapreduce? 来源:about云 http://www.aboutyu ...
- System.Rtti.TRttiObject.GetAttributes 简例
MAttribute = class(TCustomAttribute) private FName: string; public constructor Create(AName: string) ...
- cmake编译win下64位obs
obs是一款开源编码推流工具,简单易用,非常流行.一次项目中,发现本台式机I3处理器下32位obs推流CPU使用率100%.而使用的第三方设备在64位下,性能较好.所以需要编译64位obs并且编译相应 ...
- Java邮件服务学习之一:邮件服务概述
java可以提供邮件服务:一般理解的邮件服务就是可以发送和接收邮件的客户端,另外就是使用java编写邮件服务端:两者区别在于客户端只负责给终端客户收发邮件,就相当于小区楼下的那一排排的铁皮邮箱盒,而邮 ...