1

在我的一个 wp8 应用程序中,我使用BindingReflector来启用对转换器参数的绑定。我遇到的一个问题是,任何高于(在 XAML 中)在参数上使用绑定的转换器根本不会被 GC。我注意到使用此特定顺序的页面在导航到它然后返回并重复时会获得越来越多的内存。

在试图弄清楚发生了什么之后,我决定尝试更改它们在 XAML 中的顺序,使之在顶部使用反射器,问题就解决了。我想知道是否有人对此有任何解释。

当我遇到这个内存泄漏问题时,在GC Roots下的分析器显示我的转换器都在使用带有Handle (WeakRef)的反射器引用(不是直接)转换器。不知道怎么会发生这种情况,但是现在一旦它们出现故障,一切都很好,并且可以正确地进行 GC。

请注意,转换器都在兄弟控件中,结构基本上是这样的列表框:

<ListBox ItemsSource={Binding...}>
   <!-- ... item template like below -->
   <controlX propX={Binding xxx, converter=....}/>
   <controlY propY={Binding yyy, converter=....}/>
   ...
</ListBox>

编辑: 我创建并上传了一个简单的测试项目,您可以从这里下载 zip。运行应用程序,一旦 MainPage 加载,单击将您带到 Page1.xaml 的按钮,点击后退按钮,然后再次单击将您带到 Page1.xaml 的按钮并重复此过程。

我在每个页面的标题下都包含了显示当前内存使用情况的计数器,你不会注意到那里的任何东西,但接下来的 3 个计数器是

  1. Page1 对象的当前实例计数(黄色)
  2. 随机转换器对象的当前实例计数(红色)
  3. 使用绑定反射器对象的转换器的当前实例计数(绿色)

您会注意到,虽然黄色和绿色永远不会超过 3,但当您在 ​​MainPage.xaml 和 Page1.xaml 之间来回切换时,红色会继续上升。

现在,使用 Page1.xaml 中的转换器切换 2 个按钮控件的位置,只需将它们注释掉并取消注释它们下面的那些,您会注意到所有 3 个计数器都不会超过 3。

编辑2: 显然这不仅仅是绑定反射器。让两个按钮使用相同的转换器将导致特定的转换器实例不被 GC。我不知道为什么会这样。。

4

1 回答 1

2

到目前为止我发现了什么:

  • 泄漏以某种方式与 DataTemplate 相关联。如果我将控件放在 DataTemplate 之外,我将无法重现它。此外,即使控件是在页面资源中未使用的 DataTemplate 中声明的,也会发生泄漏
  • 没有 GCRoot 可以解释该对象不是垃圾收集的。所以引用可能由一些内部本机对象持有。我已经注意到可能发生这种情况的情况:http: //blogs.codes-sources.com/kookiz/archive/2013/02/17/wpdev-memory-leak-with-bitmapimage.aspx
  • 正如您在评论中提到的那样,可以通过两个按钮引用同一个转换器来重现泄漏。如果两个按钮引用相同转换器类型的单独实例,则不会发生泄漏。因此,我猜 Silverlight 运行时在初始化 DataTemplate 时会以某种方式弄乱它的引用计数。

解决方法:

我有胆量认为泄漏来自在 DataTemplate 中引用一个已从模板范围之外声明的对象(在您的情况下是转换器,但它也让我想起了涉及附加属性的类似泄漏)。在寻找一种在同一范围内声明转换器的方法时,我设法找到了一种解决方法:

坐下,深呼吸。打开泄漏转换器的类(在您的情况下为RandomConverter)。使其继承形式FrameworkElement。泄漏已修复。

……别问了。

这种解决方法实际上是找出内存分配问题所在的好方法。我会在接下来的几天里尝试进一步挖掘,但不要期望太多。

于 2013-03-31T12:06:00.097 回答