調試時使用 WorkflowInvoker 發生瘋狂的內存洩漏 (Crazy memory leak with WorkflowInvoker while debugging)


問題描述

調試時使用 WorkflowInvoker 發生瘋狂的內存洩漏 (Crazy memory leak with WorkflowInvoker while debugging)

EDIT: It seems my question suffers from TL;DR syndrome. So instead of reading the question, you may opt to see a video I've found demonstrating the issue: http://www.youtube.com/watch?v=xD0mRWJazis. Not shown in the video: it only happens while the debugger is attached.


I have an application that uses the WorkflowInvoker from Windows Workflow Foundation 4.0. It seems that while the Visual Studio 2010 debugger is attached to the process, each time I call WorkflowInvoker.Invoke(...) the process size grows by about 440 KB, until the process grows to a few gigabytes and my computer runs out of memory leading to the application freezing and the debugger crashing (my application only takes a minute or so to get there). When the debugger is not attached, no memory leaks occur.

As shown in the screenshot above, every time a workflow is invoked, Visual Studio's status bar shows Loading symbols for Workflow... even though it executes the same workflow. I'm guessing this has something to do with the memory leak. I tried disabling symbol loading by going to Tools > Options > Debugging > Symbols and under Automatically load symbols for I selected Only specified modules and made sure there are no modules specified. This did not help, the process size still grew steadily and Visual Studio still loaded workflow symbols.

Below is the minimal code to repro the issue. Look at Task Manager while running it with and without a debugger (careful, it'll eat up memory very quickly when debugging!):

var workflow = new WorkflowInvoker(new Sequence());

while (true)
    workflow.Invoke();   ////  Memory leak!  //// 

A more expanded console program demonstrating the issue while displaying memory consumption is included below. It only runs at about 100 empty workflows per second. Try running it without debugging (Ctrl+F5) and compare it to running it with debugging (F5). You'll see the difference immediately. If you'd rather not run the sample, I included the results as screenshots below.

using System;
using System.Activities;
using System.Activities.Statements;
using System.Diagnostics;
using System.Threading;

class Program
{
    static Timer Timer = new Timer(PrintMemory, null, 1000, 1000);
    static double PreviousSize;

    static void Main(string[] args)
    {
        Console.WriteLine("Debugger {0} attached.",
            Debugger.IsAttached ? "IS" : "is NOT");

        var workflow = new WorkflowInvoker(new Sequence());

        while (true)
        {
            workflow.Invoke();   ////  Memory leak!  ////
            Thread.Sleep(10);
        }
    }

    static void PrintMemory(object o)
    {
        double newSize = Process.GetCurrentProcess().PrivateMemorySize64 / 1048576d;
        Console.WriteLine("Grew by {0,5:F2} MB (total {1,7:F2} MB)",
            newSize - PreviousSize, newSize);
        PreviousSize = newSize;
    }
}

Here's a 30-second run of the program without and with debugging:

As you can see, the memory grows by around 43 MB every seconds. I must be able to run my application under the debugger. Any suggestions?

EDIT: I've opened a Connect bug for this issue here.

EDIT: Well that was a bust. Apparently Connect is only for the latest and greatest. VS2012 has RTMed a whole ten minutes ago but connect isn't accepting any feedback for VS2010 anymore. My next stop: a post on the WF4 forum. Fingers crossed.


參考解法

方法 1:

As Tim Lovell-Smith correctly noted in the MSDN Forums question I posted, this is a known bug in .NET 4.0 which was fixed in .NET 4.5. Fortunately, simply installing .NET 4.5 fixes the issue for Visual Studio 2010 as well.

方法 2:

Sounds like an Heisenbug to me and not very surprising as @dbam987 already pointer out that the garbage collector works differently when debugging than a normal build.

If you want to know about the memory behavior of your app the only way you should be testing is with a release build not running with a debugger attached. For that matter don't even start it from VS2012 without debugging, launch it from the explorer.

Given that you pointed out that there is no memory leak without the debugger I would say you don't have anything to worry about. So this only turns into a Heisenbug when you start looking for one.

方法 3:

Give launching your workflow using the WorkflowApplication component rather than the WorkflowInvoker a try. Its setup is very similar to using the WorkflowInvoker.

using System;
using System.Activities.Statements;
using System.Threading;

public class Program
{
    public static void Main(string[] args)
    {
        // Setup the sample workflow.
        var workflow = new Sequence
            {
                Activities =
                    {
                        new WriteLine { Text = "Hello World!" },
                        new Delay { Duration = TimeSpan.FromSeconds(3) },
                        new WriteLine { Text = "Done!" }
                    }
            };

        // Setup the workflow host.
        var syncWorkflowEvent = new AutoResetEvent(false);
        var workflowApp = new WorkflowApplication(workflow);
        workflowApp.Completed = eventArgs => syncWorkflowEvent.Set();
        workflowApp.Run();
        syncWorkflowEvent.WaitOne();
    }
}

(by Allon GuralnekAllon GuralnekMauriceajawad987)

參考文件

  1. Crazy memory leak with WorkflowInvoker while debugging (CC BY-SA 3.0/4.0)

#.net-4.0 #workflow-foundation-4 #.net #memory-leaks #C#






相關問題

SendKeys.Send NullReferenceException (SendKeys.Send NullReferenceException)

訪問 MarkupExtension.ProvideValue 中的構造函數參數 (Access to a constructor parameter within MarkupExtension.ProvideValue)

調試時使用 WorkflowInvoker 發生瘋狂的內存洩漏 (Crazy memory leak with WorkflowInvoker while debugging)

為跨域的 .NET Framework 靜默安裝創建部署應用程序? (Creating a deployment application for .NET Framework silent install across domain?)

Windows 窗體關閉後刪除的窗體數據 (Form data erased after Windows form is closed)

如何從 php wordpress 服務器呈現 aspx 頁面 (How to render an aspx page from a php wordpress server)

嘗試通過方法“System.Web.Helpers.Json.Decode(System.String)”訪問字段“System.Web.Helpers.Json._serializer”失敗 (Attempt by method 'System.Web.Helpers.Json.Decode(System.String)' to access field 'System.Web.Helpers.Json._serializer' failed)

如何使用 Windows 資源管理器顯示項目和詳細信息展開/折疊 (How to Display Items and Details with Windows Explorer Expand/Collapse)

在 C# 中通過反射訪問屬性 (Accessing attribute via reflection in C#)

連續輸入時不要引發 TextChanged (Don't raise TextChanged while continuous typing)

MSMQ 異步異常行為 - .NET 4.0 與 .NET 2.0 (MSMQ asynchronous exception behavior - .NET 4.0 vs .NET 2.0)

多線程 WMI 調用 - 如何最好地處理這個? (Multithreading WMI calls - how best to handle this?)







留言討論