【问题标题】:TextBox.Text Leaking Memory in WPF ApplicationWPF 应用程序中的 TextBox.Text 泄漏内存
【发布时间】:2011-03-21 04:43:59
【问题描述】:

我有一个应用程序对一组数字进行大量数字运算。我将其设置为每 100,000 次操作以显示这些数字的状态。这只是对操作员的一种视觉指示,表明应用程序仍在处理,以及距离完成还有多远。

在运行应用程序几个小时后,它崩溃并出现 OutOfMemoryExeption。我在上面运行了 CLRProfiler,发现在显示数组当前状态的 TextBox 中发生了泄漏......每次界面更新时,应用程序都会在 Char[] 中构建 ~4K,每个位的堆栈跟踪挂起内存是一样的。

这是 WPF 中的一个错误,还是我不知道我应该做些什么来防止这种情况发生?我没有看到任何其他对此的引用。由于无论如何这是一个相当密集的处理器操作,如果我不必只显示数组的当前状态,我宁愿不必销毁和重建 TextBox。

这是我能找到的唯一内存泄漏,但由于需要大量的操作,这对应用程序来说实际上是一个大问题,即使我只是降低了界面更新的频率。如果您需要更多信息,我会尽可能提供帮助,但请理解,由于此应用程序的作用,我几乎无法发布任何源代码,并且我必须匿名任何内容(删除任何关于应用程序的目的),我可以发布。

当通过 CLR Profiler 运行时,这会大大降低性能,以下相同的跟踪每 2 秒发生一次(请记住:100,000 次操作)并且永远不会释放内存。当它在没有附加分析器的情况下运行时,更新之间的时间为

来自一次更新(“谁分配”)的跟踪是:

<root> :  3.7 kB    (100.00%)
 WpfApplication0.App::Main static void ():  3.7 kB    (100.00%)
  System.Windows.Application::Run int32 ():  3.7 kB    (100.00%)
   System.Windows.Application::Run int32 (System.Windows.Window):  3.7 kB    (100.00%)
    System.Windows.Application::RunInternal int32 (System.Windows.Window):  3.7 kB    (100.00%)
     System.Windows.Application::RunDispatcher Object (Object):  3.7 kB    (100.00%)
      System.Windows.Threading.Dispatcher::Run static void ():  3.7 kB    (100.00%)
       System.Windows.Threading.Dispatcher::PushFrame static void (System.Windows.Threading.DispatcherFrame):  3.7 kB    (100.00%)
        System.Windows.Threading.Dispatcher::PushFrameImpl void (System.Windows.Threading.DispatcherFrame):  3.7 kB    (100.00%)
         NATIVE FUNCTION ( UNKNOWN ARGUMENTS ):  3.7 kB    (100.00%)
          MS.Win32.HwndSubclass::SubclassWndProc int_ptr (int_ptr int32 int_ptr int_ptr):  3.7 kB    (100.00%)
           System.Windows.Threading.Dispatcher::Invoke Object (System.Windows.Threading.DispatcherPriority  Object):  3.7 kB    (100.00%)
            System.Windows.Threading.Dispatcher::InvokeImpl Object (System.Windows.Threading.DispatcherPriority   Object bool):  3.7 kB    (100.00%)
             System.Windows.Threading.Dispatcher::WrappedInvoke Object ( Object bool ):  3.7 kB    (100.00%)
              System.Windows.Threading.ExceptionWrapper::TryCatchWhen Object (Object  Object bool ):  3.7 kB    (100.00%)
               System.Windows.Threading.ExceptionWrapper::InternalRealCall Object ( Object bool):  3.7 kB    (100.00%)
                MS.Win32.HwndSubclass::DispatcherCallbackOperation Object (Object):  3.7 kB    (100.00%)
                 MS.Win32.HwndWrapper::WndProc int_ptr (int_ptr int32 int_ptr int_ptr bool&):  3.7 kB    (100.00%)
                  System.Windows.Threading.Dispatcher::WndProcHook int_ptr (int_ptr int32 int_ptr int_ptr bool&):  3.7 kB    (100.00%)
                   System.Windows.Threading.Dispatcher::ProcessQueue void ():  3.7 kB    (100.00%)
                    System.Windows.Threading.DispatcherOperation::Invoke Object ():  3.7 kB    (100.00%)
                     System.Threading.ExecutionContext::Run static void (System.Threading.ExecutionContext System.Threading.ContextCallback Object):  3.7 kB    (100.00%)
                      System.Threading.ExecutionContext::RunInternal static void (System.Threading.ExecutionContext System.Threading.ContextCallback Object):  3.7 kB    (100.00%)
                       System.Threading.ExecutionContext::runTryCode static void (Object):  3.7 kB    (100.00%)
                        System.Windows.Threading.DispatcherOperation::InvokeInSecurityContext static void (Object):  3.7 kB    (100.00%)
                         System.Windows.Threading.DispatcherOperation::InvokeImpl void ():  3.7 kB    (100.00%)
                          System.Windows.Threading.Dispatcher::WrappedInvoke(1) Object ( Object bool ):  3.7 kB    (100.00%)
                           System.Windows.Threading.ExceptionWrapper::TryCatchWhen(1) Object (Object  Object bool ):  3.7 kB    (100.00%)
                            System.Windows.Threading.ExceptionWrapper::InternalRealCall(1) Object ( Object bool):  3.7 kB    (100.00%)
                             System.Delegate::DynamicInvokeImpl Object (Object[]):  3.7 kB    (100.00%)
                              System.Reflection.RuntimeMethodInfo::Invoke Object (Object System.Reflection.BindingFlags System.Reflection.Binder Object[] System.Globalization.CultureInfo bool):  3.7 kB    (100.00%)
                               System.RuntimeMethodHandle::InvokeMethodFast Object (Object Object[] System.Signature System.Reflection.MethodAttributes System.RuntimeTypeHandle):  3.7 kB    (100.00%)
                                WpfApplication0.Window1::UpdateUI void ():  3.7 kB    (100.00%)
                                 System.Windows.Controls.TextBox::set_Text void (String):  3.7 kB    (100.00%)
                                  System.Windows.DependencyObject::SetValue void (System.Windows.DependencyProperty Object):  3.7 kB    (100.00%)
                                   System.Windows.DependencyObject::SetValueCommon void (System.Windows.DependencyProperty Object System.Windows.PropertyMetadata bool System.Windows.OperationType bool):  3.7 kB    (100.00%)
                                    System.Windows.DependencyObject::UpdateEffectiveValue System.Windows.UpdateResult (System.Windows.EntryIndex System.Windows.DependencyProperty System.Windows.PropertyMetadata System.Windows.EffectiveValueEntry System.Windows.EffectiveValueEntry& bool System.Windows.OperationType):  3.7 kB    (100.00%)
                                     System.Windows.DependencyObject::NotifyPropertyChange void (System.Windows.DependencyPropertyChangedEventArgs):  3.7 kB    (100.00%)
                                      System.Windows.Controls.TextBox::OnPropertyChanged void ():  3.7 kB    (100.00%)
                                       System.Windows.FrameworkElement::OnPropertyChanged void ():  3.7 kB    (100.00%)
                                        System.Windows.DependencyObject::OnPropertyChanged void (System.Windows.DependencyPropertyChangedEventArgs):  3.7 kB    (100.00%)
                                         System.Windows.Controls.TextBox::OnTextPropertyChanged static void ( ):  3.7 kB    (100.00%)
                                          System.Windows.Documents.TextContainer::DeleteContentInternal void (System.Windows.Documents.TextPointer System.Windows.Documents.TextPointer):  3.7 kB    (100.00%)
                                           System.Windows.Documents.TextTreeUndo::CreateDeleteContentUndoUnit static System.Windows.Documents.TextTreeDeleteContentUndoUnit (System.Windows.Documents.TextContainer System.Windows.Documents.TextPointer System.Windows.Documents.TextPointer):  3.7 kB    (100.00%)
                                            System.Windows.Documents.TextTreeDeleteContentUndoUnit::.ctor void (System.Windows.Documents.TextContainer System.Windows.Documents.TextPointer System.Windows.Documents.TextPointer):  3.7 kB    (100.00%)
                                             System.Windows.Documents.TextTreeDeleteContentUndoUnit::CopyContent ContentContainer (System.Windows.Documents.TextTreeNode System.Windows.Documents.TextTreeNode):  3.7 kB    (100.00%)
                                              System.Windows.Documents.TextTreeDeleteContentUndoUnit::CopyTextNode System.Windows.Documents.TextTreeNode (System.Windows.Documents.TextTreeTextNode System.Windows.Documents.TextTreeNode ContentContainer&):  3.7 kB    (100.00%)
                                               System.Char [] :  3.7 kB    (100.00%)

生成 UI 更新的代码是:

        List<int> arraystatus = new List<int>(displayarray.ToArray());

        StringBuilder s = new StringBuilder();

        int i = 1;

        foreach (int item in arraystatus)
        {
            s.Append(i.ToString() + ":\t" + item.ToString() + (i % 8 == 0 ? "\n" : "\t"));
            i++;
        }

        txtStatus.Text = s.ToString();

        arraystatus = null;
        s = null;

【问题讨论】:

  • 这是 WPF 中的错误吗? 99% 肯定没有。你在分配弦乐碎片吗?可能是,从您的代码中不确定。有没有更好的办法?大概吧。
  • 另外,调试时通常不会释放内存;在发行版中运行时会发生这种情况吗?
  • 从字面上看,这是在最初创建 UI 之后创建字符串的唯一一段代码。它封装在一个方法中,调度程序每 100,000 次操作从我的工作线程调用该方法。是的,它有很多字符串。我的问题是“他们为什么不离开?”。是的,它发生在发布或调试中。
  • @lukas GC.Collect 不适合您。不是你的。一旦你开始在代码中输入 G 和 C,你就已经做错了。
  • 我认为他的意思是用它作为测试,看看这是否只是 GC 不自信的情况。

标签: c# wpf memory-leaks textbox


【解决方案1】:

来自 TextBoxBase.UndoLimit 属性的文档:

存储在撤消队列中的操作数。默认值为 –1,即 意味着撤消队列仅限于 可用内存。

你找到了那个限制。将其设置为相当小的值。

否则,在 TextBox 中显示日志信息通常没有多大意义。它实际上是为了允许用户输入文本。也许 TextBlock 是更好的选择。


更新:在 .NET 4.5 中,默认值 -1 已更改为 100,以避免这种失控的内存使用。

【讨论】:

  • 很好地抓住了这一点......它现在运行平稳,没有泄漏。谢谢! +1 并接受。
  • * 擦掉溢出的失败酱 *
【解决方案2】:

为汉斯+1。

另外,您正在使用 StringBuilder。太棒了。

但是,每次更新 UI 时,您都会为 arraystatus 中的每个项目连接四个字符串(据我所知,这可能是 100k),这使得 StringBuilder 几乎毫无意义。

试试

s.Append(i.ToString());
s.Append(":\t");
s.Append(item.ToString());
s.Append(i % 8 == 0 ? "\n" : "\t"));

或者,更好的是,尝试将其转换为单个调用 AppendFormat

【讨论】:

  • 是的,我的愚蠢在那里,显然有一天我在写作时没想到...... +1
猜你喜欢
  • 2010-11-27
  • 1970-01-01
  • 2012-04-30
  • 1970-01-01
  • 2017-03-29
  • 1970-01-01
  • 2014-01-02
  • 2016-03-28
  • 1970-01-01
相关资源
最近更新 更多