WPF应用程序中的线程抛出System.OutOfMemoryException异常

4
以下代码将在应用程序进行处理时调用另一个线程以显示进度窗口。如果我们多次执行,例如超过50次,则会抛出异常。 这是我们的代码-BusyIndicatorHelper.ShowProgWindowCustomSize作为异常抛出,并将调用以下代码。
public void ShowBusyIndicatorCustomSize(string message, WindowCustom currentWindow, bool fileTransferStatus = false)
{
    _message = message;
    using (_progressWindowWaitHandle = new AutoResetEvent(false))
    {
        _transferLoadVisibility = fileTransferStatus;
        //Starts the progress window thread
        Thread newprogWindowThread = new Thread(() => ShowProgWindowCustomSize(currentWindow));  
        //new Thread(new ThreadStart(ShowProgWindowNew(height, width, left, right)));
        newprogWindowThread.SetApartmentState(ApartmentState.STA);
        newprogWindowThread.IsBackground = true;
        newprogWindowThread.Start();

        //Wait for thread to notify that it has created the window
        _progressWindowWaitHandle.WaitOne();
        _isActive = true;
    }
}

这将调用ShowProgWindowCustomSize(currentWindow),如以下所示。
private void ShowProgWindowCustomSize(WindowCustom currentWindow)
    {
        if (_transferLoadVisibility)
        {
            //creates and shows the progress window
            progWindow = new LoadingWindow(_message);
            progWindow.Height = currentWindow.WindowHeight;
            progWindow.Width = currentWindow.WindowWidth;
            progWindow.Left = currentWindow.WindowLeft;
            progWindow.Top = currentWindow.WindowTop;
            progWindow.WindowState = currentWindow.WindowState;

            progWindow.FileTansfer();
            progWindow.Show();
        }
        else
        {
            //creates and shows the progress window
            progWindow = new LoadingWindow(_message);
            progWindow.Height = currentWindow.WindowHeight;
            progWindow.Width = currentWindow.WindowWidth;
            progWindow.Left = currentWindow.WindowLeft;
            progWindow.Top = currentWindow.WindowTop;
            progWindow.WindowState = currentWindow.WindowState;
            progWindow.Show();
        }

        //makes sure dispatcher is shut down when the window is closed
        progWindow.Closed += (s, e) => Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);

        //Notifies command thread the window has been created
        _progressWindowWaitHandle.Set();

        //Starts window dispatcher
        System.Windows.Threading.Dispatcher.Run();
    }

以下是抛出outofmemory异常的情况。
应用程序: BioMedicalVerification.exe 框架版本: v4.0.30319 描述: 由于未处理的异常,进程已终止。 异常信息: System.OutOfMemoryException 堆栈: System.Windows.Media.Composition.DUCE+Channel.SyncFlush() System.Windows.Media.MediaContext.CompleteRender() System.Windows.Interop.HwndTarget.OnResize() System.Windows.Interop.HwndTarget.HandleMessage (MS.Internal.Interop.WindowMessage, IntPtr, IntPtr) System.Windows.Interop.HwndSource.HwndTargetFilterMessage (IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef) MS.Win32.HwndWrapper.WndProc(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef) MS.Win32.HwndSubclass.DispatcherCallbackOperation(System.Object) System.Windows.Threading.ExceptionWrapper.InternalRealCall (System.Delegate, System.Object, Int32) System.Windows.Threading.ExceptionWrapper.TryCatchWhen (System.Object, System.Delegate, System.Object, Int32, System.Delegate) System.Windows.Threading.Dispatcher.LegacyInvokeImpl (System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, System.Object, Int32) MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr) MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr) MS.Win32.HwndSubclass.DefWndProcWrapper(IntPtr, Int32, IntPtr, IntPtr) MS.Win32.UnsafeNativeMethods.CallWindowProc(IntPtr, IntPtr, Int32, IntPtr, IntPtr) MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr) MS.Win32.UnsafeNativeMethods.SetWindowPos(System.Runtime.InteropServices.HandleRef, System.Runtime.InteropServices.HandleRef, Int32, Int32, Int32, Int32, Int32) System.Windows.Window.SetupInitialState(Double, Double, Double, Double) System.Windows.Window.CreateSourceWindow(Boolean) System.Windows.Window.CreateSourceWindowDuringShow() System.Windows.Window.SafeCreateWindowDuringShow() System.Windows.Window.ShowHelper(System.Object) System.Windows.Window.Show() Org.Bestinet.BV.Presentation.UI.BusyIndicatorHelper.ShowProgWindowCustomSize (Org.Bestinet.BV.Presentation.UI.WindowCustom) Org.Bestinet.BV.Presentation.UI.BusyIndicatorHelper+<> c__DisplayClass2.<ShowBusyIndicatorCustomSize>b__0() System.Threading.ThreadHelper.ThreadStart_Context(System.Object) System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) System.Threading.ThreadHelper.ThreadStart()
我怀疑问题出在VerifyFinger函数上,因为我们在这里检查指纹图像。
BusyIndicatorHelper busyIndicatorHelper = new BusyIndicatorHelper();
List<WorkerDO> docList = new         
DatabaseHelper().SearchDocInfo(UserContext.VdrInfo.WorkerObj.WrkrId);

if (docList != null && docList.Count > 0)
{   busyIndicatorHelper.ShowBusyIndicatorCustomSize("Verification",  
    WindowSetting.GetCurrentWindowState(this));

    FingerPrintHelper fp = null;
    if (_fpHelper != null)
       fp = _fpHelper;
    else
       fp = FingerPrintHelper.GetFingerPrinterHelperObj;

    verifyStatus = fp.VerifyFinger(docList, _viewModel.DetectedFingers,  
    IsIndexFingerSelected);
    docList = null;
    _viewModel.DetectedFingers = null;
}

2
这与“等待”对话框无关,而是与在此窗口显示时执行的逻辑有关。你向我们展示了该窗口的源代码,但它没有任何意义。相反,你应该展示在此窗口显示时正在发生什么。 - user586399
你能分享WindowCustom的代码吗?包括XAML和codebehind两部分?这可能与它内部发生的事情有关。 - VidasV
3个回答

2
为什么要关闭CurrentDispatcher?它是你的程序中唯一的一个,而且你的代码永远不会执行关闭操作。所以每次打开BusyWindow时,都会创建一个新线程(从内存中减去1MB),并进入无限循环,消耗系统资源的另一部分。最终你的程序将耗尽内存,这正如你的异常所述。
你真的不应该为你的任务启动一个新线程——使用更高级别的抽象,比如ThreadPoolTask Parallel Library。这将有助于消除你代码中的内存泄漏问题。
更新:
我在你的新代码中看到这样一行:
_viewModel.DetectedFingers = null;

我怀疑这是客户提供的 图像。如果是的话,你不能简单地将其设置为 null,你必须使用 Dispose() 方法释放你的图形资源,像这样:
verifyStatus = fp.VerifyFinger(docList, _viewModel.DetectedFingers,  
IsIndexFingerSelected);
docList = null;
_viewModel.DetectedFingers.Dispose();
_viewModel.DetectedFingers = null;

_viewModel.DetectedFingers是一个包含图像对象的FingerPrintDetails对象列表。我认为可能是因为这个原因,所以将对其进行处理并在此更新结果。 - Hash
即使在_viewModel.DetectedFingers列表中处理了图像对象,问题仍未得到解决。在以下代码行仍然会出现内存不足的情况。 progWindow.Closed += (s, e) => Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background); - Hash
然后删除线程创建,正如我之前所说 - 你有很多线程,它们似乎没有正确关闭。 - VMAtm

0
问题已经找到。不是因为 WPF 代码的问题,而是由于我们使用的 SDK 内存不足。
问题已解决。谢谢。

-1
每次调用此方法时,您都会在新线程上创建一个新的LoadingWindow对象。 progWindow = new LoadingWindow(_message);
在创建新对象之前,您是否释放了先前的LoadingWindow?

我使用以下代码关闭了线程,这是标准的关闭线程代码。public void HideBusyIndicator() { //关闭进度窗口 if(_isActive) progWindow.Dispatcher.Invoke(new Action(progWindow.Close)); _isActive = false; } - Hash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接