我的Flex应用程序中存在一些内存泄漏问题,我的问题的简短版本是:有没有办法(在AcitonScript 3中)查找给定对象的所有实时引用?
我所拥有的是一些视图背后的演示模型(使用Swiz)。感兴趣的视图是TabNavigator的子视图,因此当我关闭选项卡时,视图将从舞台中删除。从阶段中删除视图时,Swiz会将视图中的模型引用设置为null,就像它应该的那样。我也从视图中删除了AllChildren()。
但是,在分析应用程序时,当我执行此操作并运行GC时,视图和表示模型都不会被释放(尽管两者都将它们的引用设置为null)。视图使用的一个模型对象(虽然不是演示者)被释放,因此它没有完全被破坏。
我今天刚刚开始进行剖析(坚信不要过早地进行优化),所以我想有某种参考漂浮在某个地方,但我看不到哪里,以及什么是超级有用的将是调试和查看引用目标对象的对象列表的能力。这一切都是可能的,如果不是原生的话,是否有一些轻量级的方法将其编码到未来的应用程序中以进行调试?
干杯。
答案 0 :(得分:11)
假设您使用的是Flex Builder,您可以尝试使用Profiler。根据我的经验,它对于分析性能并不是很好,但它对于发现内存泄漏非常有帮助。
这不是最直观的工具,需要一段时间才能适应它(我的意思是,它实际上变得有用了)。但是,在我看来,投入一些时间来至少学习基础知识是值得的。只看到玩家在全球范围内使用了多少内存(System.totalMemory给你的内容,一个非常粗略,不精确且经常误导的指标)并且实际跟踪每个对象创建了多少个实例,仍有多少仍然存在巨大差异活着和他们分配的位置(所以你可以在代码中找到潜在的泄漏并实际修复它而不是依赖于黑魔法)。
我不知道FB Profiler有什么好的教程,但也许这对你有所帮助。
首先,启动探查器。取消选中性能分析并检查其他所有内容(启用内存分析,查看实时内存数据并生成对象分配堆栈跟踪)。
当探查器启动时,您将看到按类分组的应用程序对象的统计信息。此时,您可能想要调整过滤器。你会看到很多数据,很容易被淹没。现在,如果可能的话,忽略flash和flex中的所有东西,并专注于你认为应该收集的一些对象。
最重要的数字是“累积实例”和“实例”。第一个是到目前为止创建的实例总数;第二,所述实例的数量仍然存在。因此,一个好的起点是让您的应用程序进入您怀疑泄漏被创建的视图所在的状态。您应该看到“累积实例”和“实例”1。
现在,做任何你需要做的事情来达到应该清理这个视图的点(导航到应用程序的其他部分等)并运行GC(在探查器UI中有一个按钮)。关键的一点是,您将根据您的期望检查应用行为 - 如果这是有道理的。根据定义,在收集环境中自动发现泄漏几乎是不可能的;否则,就不会有泄漏。所以,记住这一点:你测试你的期望;你是那个知道你的物体生命周期的人,可以说,“此时这个物体应该被收集;如果不是,就会出现问题。”
现在,如果您的视图的“实例”计数下降到0,那么就没有泄漏。如果您认为应用程序泄漏,请尝试查找可能未正确处理的其他对象。如果计数保持为1,则表示您的视图已泄露。现在,你必须找到原因和地点。
此时,您应该拍摄“内存快照”(Force GC按钮旁边的按钮)。打开快照,在网格中找到对象并双击它。这将为您提供所有引用此对象的对象的列表。它实际上是一棵树,可能每个项目都会包含许多反向引用等等。这些是阻止收集视图的对象。在右侧面板中,您还将获得分配跟踪。这将显示如何创建所选对象(非常像堆栈跟踪)。
你可能会看到那里有很多物体。但最好的办法是专注于那些生命周期比你正在检查的对象(你的观点)更长的人。我的意思是,寻找舞台,父母观点等;视图所依赖的对象,而不是依赖于视图的对象,如果这有意义的话。如果您的视图有一个按钮并且您添加了一个监听器,那么您的按钮将具有您的视图的参考。在大多数情况下,这不是问题,因为按钮取决于视图,一旦收集视图,按钮也是如此。因此,我们的想法是,由于有很多物体,你应该保持专注,否则你将无处可去。这种方法颇具启发性,但根据我的经验,它可行。
一旦找到泄漏源,请返回源代码,相应地更改代码(可能这不仅需要更改代码,还需要重构一点)。然后重复此过程并检查您的更改是否已产生预期效果。这可能需要一段时间,具体取决于您的应用程序的大小或复杂程度以及您对它的了解程度。但如果你一步一步地找到并解决一个问题,你最终会摆脱泄漏。或者至少是最糟糕的,更明显的。所以,虽然有点单调乏味,但它会得到回报(并且作为一个好的方面,你最终会明白在大多数情况下浪费时间来为地球上的每一个事件处理程序使用弱refs,将每个事件都归零单变量等等;这是一种启发性的体验;)。
希望这有帮助。
答案 1 :(得分:2)
Flash GC使用引用计数和标记和扫描的混合,因此它确实检测循环引用。看来你在对象图中有另一个引用。最常见的原因是,您想要处理的对象仍然具有在未处置的对象上注册的事件处理程序。您可以尝试确保处理程序始终使用弱引用进行注册。如果可能的话,您还可以覆盖所有(基类)类中的addEventListener和removeEventListener,以查看哪些侦听器已注册,以及是否有可能无法删除某些侦听器。
此外,您可以为对象编写析构函数,为ui组件清除图形并删除所有子对象,对于所有对象,删除对所有属性的引用。这样,只有你的对象被保存在RAM中,这不需要太多内存(20 B左右的小占用空间,每个变量加4 B(数字为8))。
格尔茨
back2dos
答案 2 :(得分:0)