显示 Flex 对象引用

发布于 2024-09-05 00:59:18 字数 480 浏览 8 评论 0原文

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

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

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

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

干杯。

I have a bit of a memory leak issue in my Flex application, and the short version of my question is: is there any way (in AcitonScript 3) to find all live references to a given object?

What I have is a number of views with presentation models behind each of them (using Swiz). The views of interest are children of a TabNavigator, so when I close the tab, the view is removed from the stage. When the view is removed from the stage, Swiz sets the model reference in the view to null, as it should. I also removeAllChildren() from the view.

However when profiling the application, when I do this and run a GC, neither the view nor the presentation model are freed (though both set their references to each other to null). One model object used by the view (not a presenter, though) IS freed, so it's not completely broken.

I've only just started profiling today (firmly believing in not optimising too early), so I imagine there's some kind of reference floating around somewhere, but I can't see where, and what would be super helpful would be the ability to debug and see a list of objects that reference the target object. Is this at all possible, and if not natively, is there some light-weight way to code this into future apps for debugging purposes?

Cheers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

遥远的绿洲 2024-09-12 00:59:18

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

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

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

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

当探查器启动时,您将看到有关应用程序对象的统计信息(按类分组)。此时,您可能想要调整过滤器。您会看到大量数据,很容易不知所措。现在,如果可能的话,请忽略 Flash 和 Flex 原生的所有内容,并专注于您认为应该收集的某些对象。

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

现在,执行您需要执行的操作以达到应清理此视图的程度(导航到应用程序的其他部分等)并运行 GC(分析器 UI 中有一个按钮)。关键的一点是,您将根据您的期望检查应用程序的行为 - 如果这有意义的话。根据定义,在垃圾收集环境中自动查找泄漏几乎是不可能的;否则就不会出现泄漏。因此,请记住这一点:您的测试与您的期望相反;您是了解对象生命周期的人,并且可以说:“此时该对象应该已被收集;如果没有,则存在问题”。

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

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

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

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

希望这有帮助。

Assuming you are using Flex Builder, you could try the Profiler. In my experience, it's not so good for profiling performance, but it's been of great help for finding memory leaks.

It's not the most intuitive tool and it takes a while to get used to it (I mean, to the point where it actually becomes helpful). But, in my opinion, investing some time to at least learn the basics pays off. There's an enormous difference between just seeing how much memory the player is using globally (what System.totalMemory gives you, a very rough, imprecise and often misleading indicator) and actually track how many instances of each object have been created, how many are still alive and where were they allocated (so you can find the potential leak in the code and actually fix it instead of relying in black magic).

I don't know of any good tutorials for the FB profiler, but maybe this'll help to get you started.

First, launch the profiler. Uncheck performance profiling and check everything else (Enable memory profiling, watch live memory data and generate object allocation stack traces).

When the profiler starts, you'll see stats about the app objects, grouped by class. At this point, you might want to tweak filters. You'll see a lot of data and it's very easy to be overwhelmed. For now, ignore everything native to flash and flex stuff, if possible, and concentrate on some object that you think it should be collected.

The most important figures are "cumulative instances" and "instances". The first is the total number of instances created so far; the second, the number of said instances that are still alive. So, a good starting point is get your app to the state where the view you suspect that leaks gets created. You should see 1 for "cumulative instances" and "instances".

Now, do whatever you need to do to get to the point where this view should be cleaned up (navigate to other part of the app, etc) and run a GC (there's a button for that in the profiler UI). A crucial point is that you will be checking the app behaviour against your expectations -if that makes sense-. Finding leaks automatically in a garbarge collected environment is close to impossible by definition; otherwise, there would be no leaks. So, keep that in mind: you test against your expectations; you are the one who knows the life cycle of your objects and can say, "at this point this object should have been collected; if it's not, there's something wrong".

Now, if the "instances" count for you view goes down to 0, there's no leak there. If you think the app leaks, try to find other objects that might not have been disposed properly. If the count remains at 1, it means your view is leaked. Now, you'll have to find why and where.

At this point, you should take a "memory snapshot" (the button next to the Force GC button). Open the snapshot, find the object in the grid and double click on it. This will give you a list of all the objects that have a reference to this object. It's actually a tree, and probably each item will contain in turn a number of backreferences and so on. These are the objects that are preventing your view from being collected. In the right panel, also, you will an allocation trace. This will show how the selected object was created (pretty much like a stack trace).

You'll probably see a hugh number of objects there. But your best bet is to concentrate in those that have a longer life cycle than the object you're examining (your view). What I mean is, look for stage, a parent view, etc; objects on which your view depends on rather than objets that depend on your view, if that makes sense. If your view has a button and you added a listener to it, your button will have a ref to your view. In most cases, this is not a problem, since the button depends on the view and once the view is collect, so is the button. So, the idea is that since there are a lot of objects, you should try to stay focused or you will get nowhere. This method is rather heuristic, but in my experience, it works.

Once you find the source of a leak, go back to the source, change the code accordingly (maybe this requires not just changing code but refactoring a bit). Then repeat the process and check whether your change has caused the desired effect. It might take a while, depending on how big or complex is your app and how much you know about it. But if you go step by step, finding and fixing one problem at the time, you'll eventually get rid of the leaks. Or at least the worst and more evident ones. So, while a bit tedious, it pays off (and as a nice aside, you'll eventually understand what a waste of time is in most cases to use weak refs for every single event handler on the face of this earth, nulling out every single variable, etc, etc; it's an enlightening experience ;).

Hope this helps.

笑咖 2024-09-12 00:59:18

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

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

问候
后退2dos

Flash GC uses a mix of ref counting and mark and sweep, so it does detect circular references. It seems rather you're having another reference in you object graph. The most common reason is, that the objects you want disposed still are having event handlers registered on objects that are not disposed. You could try to ensure that handlers are always registered with weak reference. You could also override addEventListener and removeEventListener in all (base) classes, if possible, to look which listeners are registered and whether there are chances for some not to be removed.

Also, you can write destructors for your objects, that for ui components clear graphics and remove all children, and for all objects, removes references to all properties. That way, only your object is kept in RAM, which shouldn't require much memory (a small footprint of 20 B or so, plus 4 B per variable (8 for a Number)).

greetz
back2dos

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文