Silverlight的MVVM + +绑定=内存泄漏? [英] Silverlight + MVVM + Bindings = Memory leaks?

查看:174
本文介绍了Silverlight的MVVM + +绑定=内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

到目前为止,我的测试表明,所有的标准方法,实例和框架利用Silverlight中的MVVM模式从一个巨大的问题的困扰:海量内存泄漏而防止虚拟机被垃圾收集

Thus far, my testing has shown that all standard approaches, examples, and frameworks leveraging the MVVM pattern in silverlight suffer from a huge problem: massive memory leaks which prevent VMs from being garbage collected.

显然,这是一个巨大的和可笑索赔 - 所以我的期望是,有人会为什么和我要去哪里错了一个显而易见的答案:)

Obviously this is a huge and ridiculous claim - so my expectation is that someone will have an obvious answer of why and where I'm going wrong :)

重现步骤很简单:


  • 通过设置视图的DataContext绑定您的视图模型到视图到VM(假设视图模型利用INotifyPropertyChanged的支持数据绑定)

  • 绑定UI元素属性的视图模型,例如:

<文本框的文本={结合SomeText}/>


  • 充分利用以某种方式结合(例如 - 只是在文本框中键入)。

此创建​​从根延伸到一BindingExpression,您的视图模型的引用链。然后,您可以从您的UI树,以及所有refernences到虚拟机删除视图 - 但VM将永远不会被垃圾收集得益于根<> BindingExpression<> VM参考链

This creates a reference chain that extends from the root, to a BindingExpression, to your viewmodel. You can then remove the View from your UI tree, as well as all refernences to the VM - however the VM will never be garbage collected thanks to the root<>BindingExpression<>VM reference chain.

我已经创建了两个例子说明问题。他们有一个按钮,创建一个新的视图/视图模型(这应该转储到旧(S)的所有引用),并迫使垃圾收集,并在当前的内存使用情况的报告的按钮。

I have created two examples illustrating the problem. They have a button to create a new view/viewmodel (which should dump all references to the old one(s)) and a button which forces garbage collection and reports on the current memory usage.

例1是一个超级精简卡利微例子。例2不使用框架,只是说明我能想到的最简单的方法的问题。

Example 1 is a super stripped down caliburn micro example. Example 2 uses no frameworks and just illustrates the problem in the simplest way I could think of.

Example 1

例2

对于那些谁可能会喜欢帮助,但不希望下载示例项目,这里是实例2的代码。我们从一个视图模型称为FooViewModel:

For those who might like to help but don't wish to download the example projects, here is the code for example 2. We start with a viewmodel called FooViewModel:

 public class FooViewModel : INotifyPropertyChanged
{
    string _fooText;

    public string FooText
    {
        get { return _fooText; }
        set
        {
            _fooText = value;
            NotifyPropertyChanged("FooText");
        }
    }

    private byte[] _data;
    public FooViewModel()
    {
        _data = new byte[10485760]; //use up 10mb of memory
    }



    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}



它只是暴露了所谓FooText的字符串属性,我们将绑定了。 。INotifyPropertyChanged的时,只需要方便的结合

It simply exposes a string property called FooText which we will bind too. INotifyPropertyChanged is neccessary to facilitate the binding.

然后,我们有一个叫做FooView认为这是一个包含用户控件:

Then we have a view called FooView which is a usercontrol containing:

<UserControl x:Class="MVVMLeak.FooView">
    <StackPanel x:Name="LayoutRoot" Orientation="Horizontal">
        <TextBlock Text="Bound textbox: " />
        <TextBox Text="{Binding FooText}" Width="100"/>
    </StackPanel>
</UserControl>



(不再赘述命名空间)

(namespaces omitted for brevity)

这里最重要的一点是它绑定到FooText属性的文本框中。当然,我们需要设置DataContext的,这是我所选择的代码隐藏做,而不是引入ViewModelLocator:

The important bit here is the textbox which is bound to the FooText property. Of course we need to set the datacontext, which I've chosen to do in the codebehind rather than introduce a ViewModelLocator:

public partial class FooView : UserControl
{
    public FooView()
    {
        InitializeComponent();
        this.DataContext = new FooViewModel();
    }
}



的MainPage看起来是这样的:

MainPage looks like this:

<StackPanel x:Name="LayoutRoot" Background="White">

    <Button Click="Button_Click" Content="Click for new FooView"/>
    <Button Click="Button2_Click" Content="Click to garbage collect"/>
    <ContentControl x:Name="myContent"></ContentControl>
</StackPanel>



在后面的代码如下:

with the following in the code behind:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        myContent.Content = new FooView();
    }

    private void Button2_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Memory in use after collection: " + (GC.GetTotalMemory(true) / 1024 / 1024).ToString() + "MB");
    }

请注意:要复制的问题,一定要在文本框中键入内容,因为我相信不会创建绑定表达式,直到它的需要。

Note: To replicate the problem, be sure to type something in the textbox, as I believe the Binding Expression isn't created until it's needed.

这是值得注意的是,的此知识库文章可能有关,但我不会因为'方法2解决办法似乎没有产生效果,并参考链似乎并不匹配信服。

It's worth noting that this KB article may be related, however I'm not convinced since 'method 2' workaround doesn't seem to have an effect, and the reference chain doesn't seem to match.

另外,我不知道它的问题,但我用的 CLR探查来诊断病因。

Also, I'm not sure it matters, but I used CLR Profiler to diagnose the cause.

更新:

如果有人想进行测试,并在评论报告了他们的发现,我主持透过Dropbox这里Silverlight应用程序:的Hosted例的。要重现:打顶钮,输入的东西,打上面的按钮,类型的东西,打顶部的按钮。然后按下按钮。如果报告10MB的使用(或者未增加其他金额),你是不是遇到了内存泄漏。

If anyone would like to test, and report their findings in a comment, I'm hosting the silverlight application via dropbox here: Hosted Example . To reproduce: Hit the top botton, type something, hit the top button, type something, hit the top button. Then hit the button. If it reports 10MB usage (or perhaps some other amount that is not increasing), you are not experiencing the memory leak.

到目前为止,这个问题似乎是发生在我们所有的开发机器,这是ThinkPad的W510(43192RU)与12GB内存,64位Win 7的企业。这包括其中一些还没有安装开发工具。它可能是值得指出的是,他们正在运行的VMware Workstation

Thus far, the problem seems to be happening on ALL of our development machines, which are ThinkPad w510 (43192RU) with 12GB Ram, 64 bit Win 7 Enterprise. This includes some which have not had development tools installed. It might be worth noting that they are running VMWare workstation.

这个问题似乎并不在其它机器上发生我曾尝试 - 包括一些家用电脑和其他电脑中办公室。我们有所排除SL版本,内存大小,大概VMware等。还没有敲定一个原因。

The problem does NOT seem to happen on other machines I have tried - including several home PCs and other PCs in the office. We have somewhat ruled out SL versions, amount of memory, and probably vmware. Still haven't nailed down a cause.

推荐答案

<击>一个解决方案是尚未被发现,但是问题现在标识。如果Silverlights会发生此行为自动化学院被调用由于:

A solution is yet to be found, however the problem is now identified. This behavior will occur if Silverlights' automation faculties are invoked due to:


  • Tablet PC输入服务(换句话说,所有的'平板电脑像'个人电脑)

  • 自动化测试工具

  • 屏幕阅读器(和其他访问性软件)

点击此处了解详情:的 http://www.wintellect.com/cs/blogs/sloscialo/archive/2011/04/13/silverlight-memory-leaks-and-automationpeers.aspx

More information here: http://www.wintellect.com/cs/blogs/sloscialo/archive/2011/04/13/silverlight-memory-leaks-and-automationpeers.aspx

因此,一个新的问题面:我们如何禁用automationpeers或以其他方式让他们清理正确

So a new problem surfaces: How do we disable automationpeers or otherwise get them to clean-up correctly?

这岗位说明了一种方法: WPF用户控件中的内存泄漏

This post illustrates one approach: WPF UserControl Memory leak

然而,这是不是真的,因为我们不得不重写,我们计划使用绑定的,更不用说复杂的控制的控制模板,每一个Silverlight控件一个可行的解决方案。

However, it isn't really a viable solution as we'd have to override every silverlight control which we plan to use binding for, not to mention the control templates of complex controls.

我会改变我的答案,如果任何人都可以找出一个好的解决办法,但现在似乎没有要为一个...

I will change my answer if anyone can identify a good solution, but for now there doesn't seem to be one...

< STRONG>编辑:

下面是一个不错的解决办法,这似乎做的工作。只需添加在你的HTML下面的参数,可以定义Silverlight对象:

Here is a nice little workaround which seems to do the job. Simply add the following parameter in your HTML where you define the silverlight object:

<param name="windowless" value="true" />

在'窗户'模式下运行的一个副作用是,自动化不起作用:)

A side-effect of running in 'windowless' mode is that automation doesn't work :)

这篇关于Silverlight的MVVM + +绑定=内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆