简体   繁体   English

TextBox.Text在WPF应用程序中泄漏内存

[英]TextBox.Text Leaking Memory in WPF Application

I have an application that does a large amount of number crunching on an array of numbers. 我有一个应用程序在数组数组上进行大量的数字运算。 I have it set to every 100,000 operations to display the status of those numbers. 我将其设置为每100,000次操作以显示这些数字的状态。 This is just sort of a visual indicator to the operator that the application is still processing, and how close it is to completed. 这只是应用程序仍处理的操作员的可视指示,以及完成的距离。

After running the application for several hours, it crashes with an OutOfMemoryExeption. 运行应用程序几个小时后,它会崩溃并出现OutOfMemoryExeption。 I ran CLRProfiler on it, and found that the leak is occurring in the TextBox that shows the current state of the array... the application builds ~4K in Char[] every time the interface updates, the stack trace for each bit of hung memory is the same. 我在上面运行了CLRProfiler,发现在TextBox中发生泄漏,显示了数组的当前状态......每次接口更新时,应用程序在Char []中构建~4K,每个位的堆栈跟踪挂起记忆是一样的。

Is this a bug in WPF, or is there something that I don't know I should be doing to prevent this from happening? 这是WPF中的一个错误,还是我不知道应该做些什么来防止这种情况发生? I've not seen any other references to this. 我没有看到任何其他参考。 Since this is a pretty processor intensive operation anyway, I'd prefer not to have to destroy and rebuild the TextBox if I don't have to just to display the current state of the array. 因为无论如何这是一个非常耗费处理器的操作,如果我不必只显示数组的当前状态,我宁愿不必销毁和重建TextBox。

This is the only memory leak that I can find, but due to the sheer number of operations required, it's actually a big problem for the application, even if I simply reduce the frequency of the interface update. 这是我能找到的唯一内存泄漏,但是由于所需的操作数量庞大,这对应用程序来说实际上是一个大问题,即使我只是降低了接口更新的频率。 If you need more information, I'll assist if at all possible, but please understand that due to what this application does, I can't post hardly any source code, and I'll have to anonymize anything (removing any indication of the application's purpose) that I CAN post. 如果您需要更多信息,我会尽可能提供帮助,但请理解由于此应用程序的作用,我几乎不能发布任何源代码,我将不得不匿名化任何内容(删除任何指示应用程序的目的)我可以发布。

When run through the CLR Profiler, which DRASTICALLY reduces performance, the following identical trace occurs every 2 seconds (remember: 100,000 operations) and the memory is never deallocated. 当通过CLR Profiler(DRASTICALLY降低性能)运行时,每2秒发生以下相同的跟踪(记住:100,000次操作)并且永远不会释放内存。 When it's running without a profiler attached, the time between updates is < 1 second. 当它在没有附加分析器的情况下运行时,更新之间的时间<1秒。

The trace from one update ("Who Allocated") is: 一次更新(“Who Allocated”)的跟踪是:

<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%)

and the code generating a UI update is: 并且生成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;

From the documentation of the TextBoxBase.UndoLimit property: 从TextBoxBase.UndoLimit属性的文档:

The number of actions stored in the undo queue. 撤消队列中存储的操作数。 The default is –1, which means the undo queue is limited to the memory that is available. 默认值为-1,表示撤消队列仅限于可用的内存。

You found that limit. 你发现了这个限制。 Set it to a reasonably small value. 将其设置为相当小的值。

It otherwise doesn't normally make a lot of sense to display logging information in a TextBox. 否则,在TextBox中显示日志记录信息通常没有多大意义。 It is really meant to allow the user to enter text. 它的确意味着允许用户输入文本。 Perhaps TextBlock is a better choice. 也许TextBlock是更好的选择。


UPDATE: in .NET 4.5, the default of -1 was changed to 100 to avoid this kind of runaway memory usage. 更新:在.NET 4.5中,默认值-1更改为100以避免这种失控的内存使用情况。

+1 for Hans. 汉斯+1。

Also, you're using StringBuilder. 此外,您正在使用StringBuilder。 Awesome. 真棒。

However, you're concatenating FOUR strings for every item in arraystatus (which could be 100k for all I know) for each time your UI is updated, making StringBuilder pretty much pointless. 但是,每次更新UI时,你都会为arraystatus每个项目连接四个字符串(对于我所知道的可能是100k),这使得StringBuilder几乎毫无意义。

Try 尝试

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

or, even better, try converting this to a single call of AppendFormat . 或者,更好的是,尝试将其转换为AppendFormat的单个调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM