您的位置:首页 > 其它

flash垃圾回收和内存泄露

2011-11-15 11:44 246 查看
GC的原子模型

之所以用"原子模型"(Atomic Model)这个词,是因为这篇文章是用来描述GC怎么样在player中工作的模型,但是不包涵其相关的技术实现或细节描述。

之所以这样是因为:

1.GC在实际中的运行行为甚为复杂并且很难区描述(就像我们其实并不知道原子是什么构成的,但是我们却可以用模型来解决问题)

2.player有时会干预GC

3.这个模型已经为我工作了很久了

Flash Player 内存管理

Flash持有的内存块被分配成很多等量的小内存块

flash会一次向操作系统申请几大块儿内存(所以flash不会经常向系统申请内存)

在flash中把从操作系统申请的一大块内存作为一个内存池,然后将内存池分割成包含很多很小且大小固定的块(block).

大的块用来存储Bitmap,文件等内存大户,而且他们是不可合并的





下载
(62.46 KB)

2010-9-7 15:37

当一个内存池用完时,flash会向操作系统再申请一大块内存.





下载
(25.85 KB)

2010-9-7 15:37

GC并不是总在运行

你不知道什么时候会垃圾回收

当某些对象被释放后,他们在内存中所占用的块(block)并不一定在下一次分配内存时被重用.

假设我们当前内存使用大小为100000bytes





下载
(31.92 KB)

2010-9-7 15:37

假设Foo实例大小为 512bytes

当分配内存时,它会占用flash内存池中新的一个512bytes单元

foo = new Foo()





下载
(32.95 KB)

2010-9-7 15:37

当我们清除一个对象所有引用后,此时对象占用的内存并没有立即被标记为未使用,只有GC将其标记为未使用后,该对象所占用的块属性才会变为未使用.

内存仍然为100512 bytes.

将其置空(销毁)并不代表其在内存中已经被释放.

System.totalMemory = 100512 bytes





下载
(38.93 KB)

2010-9-7 15:37

我们再次实例化一个新的Foo对象,它会占用flash内存池中新的单元(未使用的单元)

内存现在是101024 bytes.





下载
(42.76 KB)

2010-9-7 15:37

只有内存分配才会引发垃圾回收.

当一个内存池快被用完时,在向操作系统申请内存之前前,GC就会尝试去收集内存池.

就像影片租赁一样,他们不会去检查最近还回来的影片,而是要等货架上所有的影片都没了的时候才会去检查.





下载
(39.92 KB)

2010-9-7 15:37

只能被内存分配才会引发GC;这就意味着,你总可以在内存中看到一些未被回收的对象,并且它们一直占用内存.

GC回收一次内存并不一定会将所有的可回的对象全部回收

因此不要企图通过渲染或者交互来干预GC

这就意味内存永远不可能回复到最初的状态.





下载
(49.09 KB)

2010-9-7 15:37





下载
(49.66 KB)

2010-9-7 15:37

收集器会尽量将所有标记为"未使用"的块儿整理到同一个flash内存池中,当某一个flash内存池中所有小的单元都是"未使用"时,flash就会将其释放,返还给操作系统.

一般情况下GC不会一次就完成这一过程(译者注:在ActionScript 3.0 and

AVM2

erformance Tuning这篇文章中提及每次标记时间限制在30毫秒内).

因此内存永远都不可能恢复到出事状态.





下载
(29.63 KB)

2010-9-7 15:37





下载
(42.57 KB)

2010-9-7 15:37

由于GC是不可确定的,这就意味着你不能严格的确认你的程序是否出现了内存泄露

但是我们可以靠经验来判断。检测内存泄露

一些不起眼的事件例如timing事件,鼠标事件和键盘事件都会影响总内存。

因此交互不是一个很好的检测方法.

一般情况我们可以关注一些可重复的过程

popup对话窗口生成和删除

Modules的加载和卸载

如果在一段时间内重复执行这一过程,那么内存总量会在达到某个最高值后停止或者下降,当然前提是你的程序没有内存泄露

在flex下一次释放内存时, 就会知道否有有内存泄露的症状.

在此之前:

编写as代码使其过程自动化,即使整体流程的执行不依赖于交互.

其中一种技术就是使用switch语句并伪造鼠标和键盘事件

private function doit():void { // call this on some interval

var m:MouseEvent;

switch (currentStep)

{

case 0:

m = new MouseEvent(MouseEvent.CLICK);

b.dispatchEvent(m); // click app button to open dialog

break;

case 1:

case 2:

// wait for dialog to appear

break;

case 3:

m = new MouseEvent(MouseEvent.CLICK);

var o:Object = loginDialog;

o.b.dispatchEvent(m); // click dialog button to close dialog

case 4:

case 5:

break;

default:

currentStep = -1; // start over again

break;

}

currentStep++;

}

复制代码
去哪里找内存泄流的源头

( 原文:They will get reassigned every time through the sequence so they will drop their reference to the previous object )

1.对于一个可重复的过程, 属性引用到的对象是不会造成内存泄露的

因为每一次的执行,他们都会被重新赋值.

( 原文:Arrays, Objects used as Maps, Dictionary are common causes )

2.把Array,Objects当做Maps,Dictionnary来用,可能会引起内存泄露

(原文 : Run the sequence once, see how many things are in the arrays and object maps)

运行一次该过程,看array 或 object maps存有多少个对象

( 原文: Run it several more times, are there more things? )

运行多次再观察它们所包含的对象数量

3.没有移除监听器

GC怎样工作的

(原文:Start at known tops of Object trees. )

从已知的对象树(Object trees)的顶开始

(原文:Mark them and any objects they reference)

1.标记当前"节点"所有引用到的对象

(原文: Go through the heap and free anything that isn’t marked.)

2.检查堆,"释放"没有被标记的对象.

(Three tops of Object trees


3.对象树的3种顶层类型

(Stage)

Sttage

(ApplicationDomain/Class definitions)

ApplicationDomain/类定义(Class definitions)

(Stack/Local Variable)

栈/本地变量

Stage

从 Stage开始你可以跟随箭头(引用)找到所有的蓝色盒子(被使用对象)





下载
(53.03 KB)

2010-9-7 16:07

ApplicationDomain/Class definitions

只有静态变量会产生影响





下载
(63.29 KB)

2010-9-7 16:07

栈(stack)/本地变量(Local Variables)





下载
(68.16 KB)

2010-9-7 16:08

移除监听器

对子容器添加监听器不会引起内存泄露

下面的监听器不强制要求移除(但是移除所有监听器是一个好习惯)





下载
(73.12 KB)

2010-9-7 16:08

子容器的监听列表会保存一个父级容器事件处理函数的引用

当子容器被从父级容器中移除后,就不可能通过Stage访问到了





下载
(47.06 KB)

2010-9-7 16:08

监听父级对象时会造成内存泄露

必须要移除对父级容器的监听器





下载
(57.23 KB)

2010-9-7 16:08

有两种2个路径可以到达PopUp





下载
(59.33 KB)

2010-9-7 16:08

在这里使用弱引用可能会会更好些

除非你可以确认你和你的父级已经从显示列表中删除了.

下面的监听器不强制要求删除。





下载
(72.65 KB)

2010-9-7 16:08

总结

1..GC是内存分配引起的而非程序中的删除

2.GC时不可预测的

3.使可重复过程自动化

随着时间的推移,总内存应该会有一个最大值.

4.出乎你意料的是:事件监听会造成反向引用.

Dispatcher引用监听器

例子代码

原文ppt
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: