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. 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. 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.
Is this a bug in WPF, or is there something that I don't know I should be doing to prevent this from happening? 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.
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. When it's running without a profiler attached, the time between updates is < 1 second.
The trace from one update ("Who Allocated") is:
<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:
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;