垃圾收集器在每个帧上占用所有cpu时间的原因

时间:2014-02-20 08:45:04

标签: actionscript-3 memory-management air garbage-collection

有些时候,我的adobe air应用变得非常慢,因为垃圾收集器开始在每个帧上连续工作并占用超过800%的预算。它持续几分钟甚至更长时间。此问题仅在iPhone 4 / 4s上出现,并且在重新启动设备后,一切正常工作一段时间。

也许有人也有这样的情况并知道如何预防它?

更新:已实施对象池和其他分配防护方法。所以没有什么可以收集,GC只是花费CPU来做任何事情。当这结束时内存使用仍然是相同的。即使使用相同的输入和场景,也不会每次都发生这种情况。所以我认为存在一些“不幸”的情况,分配的堆在某个阈值附近,AIR决定在从系统中取出另一个块之前进行清理。然后它找到了几个要处理的对象,并且不再需要新的块。在下一帧中,创建的对象很少(很少),并且重复场景。

Profiler screenshot

2 个答案:

答案 0 :(得分:4)

要记住几点:

  • 当您的应用请求内存时,垃圾收集才会启动;在从操作系统请求另一个内存页面(大约大约1MB的分配)之前,Flash将尝试从您的应用程序中恢复一些内存。因为你的垃圾收集很频繁,所以它表明你的应用占用了比你想象的更多的内存
  • GC根据引用工作:var s:Sprite = new Sprite()创建对Sprite的引用。 var s2:Sprite = s创建了另一个引用。对于要考虑进行垃圾收集的Sprite的内存,ss2都需要设置为null。如果它们是局部变量,当它们超出范围时会自动发生(例如,如果它们是在函数末尾声明它们的话)
  • 清除对象的所有引用后,可以恢复分配的内存。但是,有时您可能会遇到循环引用的问题 - 其中2个对象持有对另一个的引用,但没有任何引用它们
  • 为了解决这个问题,GC一般有两个阶段:标记阶段和扫描阶段。标记阶段将从您的应用程序的根目录(舞台)开始,并尝试触摸它可以的每个对象。所有未被触及的东西都被认为是死的并且可以被收集。在扫描阶段清理所有“死”物体。
  • 标记阶段非常慢,因此您希望尽可能地避免使用它,实质上是保持内存使用不变。

帮助GC:

  • 清除事件侦听器,或使用弱侦听器(不添加引用)
  • 清除明确的引用 - 实现您想要删除某些内容时调用的destroy()dispose()方法,以及null作为对象的所有内容
  • 如上所述,使用对象池重用对象
  • 某些对象(例如BitmapDataXML)可以立即销毁(BitmapData.dispose()System.disposeXML())。如果它仅用于设置,或者可以重新加载,请将其删除。注意:如果您正在使用Starling,并且从Textures创建Bitmaps,那么您可能不需要原始版本,除非您想要处理丢失的上下文,但您可能只是加载所有内容回来。
  • 注意隐藏的分配:cacheAsBitmap在后​​台分配位图,同上filters; Array.splice()正在创建一个新阵列等
  • 注意在循环等中发生的任何对象创建

我很久以前写了一个类来帮助跟踪内存泄漏(http://divillysausages.com/blog/tracking_memory_leaks_in_as3),但你应该能够使用Scout进行更深入的了解 - 获取内存快照,玩一下,然后再拿另一个一;你可以比较两者并突出显示任何创建的对象,包括(我认为)它们的创建位置。

要记住的另一点是,如果您的设备实际上有足够的内存来运行您的应用程序 - 例如如果您的应用程序(假设一切都已经过优化等)需要100MB内存,但您只有80MB可用,那么GC将持续运行以尝试分配最后20个

答案 1 :(得分:3)

尝试使用对象池,以便回收对象。我假设您创建了大量对象,然后GC尝试释放内存,如果您回收对象,那么您将不会创建新对象而旧版本不需要被收集。如果我使用isis对象池是正确的,那么pathern会提高你的应用程序性能并可以解决你的问题。