4

我的 Flex 应用程序中有一点内存泄漏问题,我的问题的简短版本是:有没有办法(在 AcitonScript 3 中)找到对给定对象的所有实时引用?

我所拥有的是许多视图,每个视图背后都有演示模型(使用 Swiz)。感兴趣的视图是 TabNavigator 的子视图,因此当我关闭选项卡时,视图会从舞台上移除。当视图从舞台上移除时,Swiz 将视图中的模型引用设置为 null,这是它应该的。我还从视图中删除了AllChildren()。

但是,在分析应用程序时,当我这样做并运行 GC 时,视图和表示模型都没有被释放(尽管两者都将它们对彼此的引用设置为 null)。视图使用的一个模型对象(虽然不是演示者)被释放,所以它没有完全损坏。

我今天才刚刚开始分析(坚信不会过早优化),所以我想在某处有某种参考,但我看不到在哪里,而调试的能力将是超级有用的并查看引用目标对象的对象列表。这是否可能,如果不是本机,是否有一些轻量级的方法可以将其编码到未来的应用程序中以进行调试?

干杯。

4

3 回答 3

11

假设您使用的是 Flex Builder,您可以尝试 Profiler。以我的经验,它对性能分析不是那么好,但它对查找内存泄漏有很大帮助。

它不是最直观的工具,需要一段时间才能习惯(我的意思是,它实际上变得有用)。但是,在我看来,花一些时间至少学习基础知识是有回报的。仅查看玩家在全局范围内使用了多少内存(System.totalMemory 为您提供的,一个非常粗略、不精确且经常具有误导性的指标)与实际跟踪每个对象的已创建实例数、仍然存在的实例数之间存在巨大差异还活着,它们分配在哪里(因此您可以在代码中找到潜在的泄漏并实际修复它,而不是依赖黑魔法)。

我不知道 FB 分析器有什么好的教程,但也许这会帮助你入门。

首先,启动分析器。取消选中性能分析并检查其他所有内容(启用内存分析、观察实时内存数据并生成对象分配堆栈跟踪)。

当分析器启动时,您将看到有关应用程序对象的统计信息,按类分组。此时,您可能需要调整过滤器。你会看到很多数据,很容易被淹没。现在,如果可能的话,忽略所有与 flash 和 flex 相关的东西,并专注于一些你认为应该收集的对象。

最重要的数字是“累积实例”和“实例”。第一个是到目前为止创建的实例总数;第二,仍然存在的所述实例的数量。因此,一个好的起点是让您的应用程序进入您怀疑创建泄漏的视图的状态。您应该看到 1 表示“累积实例”和“实例”。

现在,做任何你需要做的事情来清理这个视图(导航到应用程序的其他部分等)并运行 GC(在分析器 UI 中有一个按钮)。一个关键点是,您将根据您的期望检查应用程序的行为——如果这有意义的话。根据定义,在垃圾收集环境中自动发现泄漏几乎是不可能的;否则,不会有泄漏。因此,请记住这一点:您根据自己的期望进行测试;你知道你的对象的生命周期,并且可以说,“此时这个对象应该被收集;如果不是,那就有问题了”。

现在,如果您查看的“实例”计数下降到 0,则说明那里没有泄漏。如果您认为应用程序泄漏,请尝试查找可能未正确处理的其他对象。如果计数仍为 1,则表示您的视图已泄漏。现在,您必须找出原因和地点。

此时,您应该拍摄“内存快照”(Force GC 按钮旁边的按钮)。打开快照,在网格中找到对象并双击它。这将为您提供引用该对象的所有对象的列表。它实际上是一棵树,并且可能每个项目将依次包含许多反向引用等等。这些是阻止您的视图被收集的对象。在右侧面板中,您还将看到分配跟踪。这将显示所选对象是如何创建的(很像堆栈跟踪)。

你可能会在那里看到大量的物体。但是你最好的选择是专注于那些生命周期比你正在检查的对象(你的观点)更长的生命周期。我的意思是,寻找舞台、父视图等;您的视图所依赖的对象,而不是依赖于您的视图的对象,如果这有意义的话。如果您的视图有一个按钮,并且您向它添加了一个侦听器,那么您的按钮将有一个对您的视图的引用。在大多数情况下,这不是问题,因为按钮取决于视图,一旦视图被收集,按钮也是如此。所以,这个想法是,既然有很多对象,你应该尽量保持专注,否则你将一事无成。这种方法是相当启发式的,但根据我的经验,它是有效的。

一旦找到泄漏的源头,就回到源头,相应地更改代码(也许这不仅需要更改代码,还需要进行一些重构)。然后重复该过程并检查您的更改是否产生了预期的效果。这可能需要一段时间,具体取决于您的应用程序的规模或复杂程度以及您对它的了解程度。但是,如果你一步一步地去,一次发现并解决一个问题,你最终会摆脱漏洞。或者至少是最糟糕和更明显的那些。所以,虽然有点乏味,但它是有回报的(顺便说一句,你最终会明白,在大多数情况下,为地球上的每个事件处理程序使用弱引用是多么浪费时间,将所有单个变量等;这是一种启发性的体验;)。

希望这可以帮助。

于 2010-06-11T05:13:39.087 回答
2

Flash GC 混合使用引用计数和标记和扫描,因此它确实检测循环引用。似乎您在对象图中有另一个引用。最常见的原因是,您想要处置的对象仍然在未处置的对象上注册了事件处理程序。您可以尝试确保始终使用弱引用注册处理程序。如果可能,您还可以覆盖所有(基)类中的 addEventListener 和 removeEventListener,以查看哪些侦听器已注册以及是否有可能不删除某些侦听器。

此外,您可以为您的对象编写析构函数,为 ui 组件清除图形并删除所有子对象,并为所有对象删除对所有属性的引用。这样,只有您的对象保存在 RAM 中,这不应该需要太多内存(大约 20 B 的小空间,加上每个变量 4 B(数字为 8))。

问候
back2dos

于 2010-06-10T14:54:10.913 回答
0

也是查找内存泄漏的有用启发式方法:http ://www.tikalk.com/flex/solving-memory-leaks-using-flash-builder-4-profiler

于 2013-05-10T12:15:02.020 回答