我的转换器没有得到GC的奇怪场景

时间:2013-03-27 17:44:46

标签: memory-leaks windows-phone-8 windows-phone

在我的一个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>

修改 我创建并上传了一个简单的测试项目,您可以download the zip from here。 运行应用程序,一旦MainPage加载,单击将您带到Page1.xaml的按钮,点击后退按钮,然后单击再次转到Page1.xaml的按钮,重复此过程。

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

  1. Page1对象的当前实例数(黄色)
  2. 随机转换器对象的当前实例计数(红色)
  3. 使用绑定反射器对象(绿色)的转换器的当前实例计数
  4. 你会注意到黄色和绿色从不超过3,当你在MainPage.xaml和Page1.xaml之间往返时,红色会继续上升。

    现在,使用Page1.xaml中的转换器切换2个按钮控件的位置,只需将它们注释掉,然后取消注释它们,你就会发现所有3个计数器都不会超过3个。

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

1 个答案:

答案 0 :(得分:2)

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

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

解决方法:

我有胆量感觉泄漏来自DataTemplate中的一个对象,该对象已经从模板范围之外声明(在您的情况下,转换器,但它也让我想起that similar leak involving an attached property) 。在寻找在同一范围内声明转换器的方法时,我设法找到了一种解决方法:

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

......不要问。

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