使用Task.Factory.FromAsync时泄漏

时间:2013-05-08 02:46:45

标签: c# memory-leaks mono

我一直在使用Task.Factory.FromAsync()方法,并且遇到了严重的内存泄漏。我使用过探查器,它表明很多物体在使用后似乎都在闲逛:

    Heap shot 140 at 98.591 secs: size: 220177584, object count: 2803125, class count: 98, roots: 666
         Bytes      Count  Average Class name
      25049168     142325      175 System.Threading.Tasks.Task<System.Int32> (bytes: +398816, count: +2266)
            1 root references (1 pinning)
            142324 references from: System.Threading.Tasks.Task
            142305 references from: System.Threading.Tasks.TaskCompletionSource<System.Int32>
            98309 references from: task_test.Task3Test.<Run>c__AnonStorey1
      25049024     142324      176 System.Threading.Tasks.Task (bytes: +398816, count: +2266)
            142304 references from: System.Threading.Tasks.TaskContinuation
      17078880     142324      120 System.Action<System.Threading.Tasks.Task<System.Int32>> (bytes: +271920, count: +2266)
            142324 references from: System.Threading.Tasks.TaskActionInvoker.ActionTaskInvoke<System.Int32>
      17076600     142305      120 System.Runtime.Remoting.Messaging.MonoMethodMessage (bytes: +271680, count: +2264)
            1 root references (1 pinning)
            142304 references from: System.MonoAsyncCall
      17076584     142305      119 System.AsyncCallback (bytes: +271920, count: +2266)
            1 root references (1 pinning)
            142304 references from: System.MonoAsyncCall
      17076584     142305      119 System.Func<System.Int32> (bytes: +271920, count: +2266)
            1 root references (1 pinning)
            142305 references from: System.Func<System.IAsyncResult,System.Int32>
            142304 references from: System.Runtime.Remoting.Messaging.AsyncResult
            1 references from: System.Func<System.AsyncCallback,System.Object,System.IAsyncResult>
      17076584     142305      119 System.Func<System.IAsyncResult,System.Int32> (bytes: +271920, count: +2266)
            1 root references (1 pinning)
            142305 references from: System.Threading.Tasks.TaskFactory.<FromAsyncBeginEnd>c__AnonStorey3A<System.Int32>
      17076480     142304      120 System.Runtime.Remoting.Messaging.AsyncResult (bytes: +271800, count: +2265)
            98461 references from: System.Object[]

我正在尝试弄清楚可能/可能不会发生什么类型的事情,以防止gc识别该对象不再使用。 FromAsync返回一个Task对象,该对象是从TaskCompletionSource获得的,它有一个类变量“source”,它保存了Task从新的Task调用中获取的值。

这是测试用例。它还包括一个使用StartNew()的情况,其中内存使用没有爆炸。下面的初始Test3Task没有使用ContinueWith但是看看它是否是我们没有清理的东西我们把它放入(没有效果)。 [并且不,下面使用的监听变量是多余的 - 有计划使测试更加智能,但是永远做得同样好。]

using System;
using System.Threading;
using System.Threading.Tasks;

namespace task_test
{
    class MainClass
    {
            public static void Main (string[] args)
            {
                    // Test3 - Leaky
                    var t = new Task3Test();

                    // Test4 - Doesn't leak
                    // var t = new Task4Test();

                    t.Run();

            }
    }

    public class BaseTask
    {
            public int GetRandomInt(int top)
            {
                    Random random = new Random();

                    return random.Next(1,top);
            }
    }

    public class FibArgs
    {
            public byte[] data;
            public int n;
    }

    public class Fib
    {
            public int Calculate(FibArgs args)
            {
                    int n = args.n;

                    int a = 0;
                    int b = 1;
                    // In N steps compute Fibonacci sequence iteratively.
                    for (int i = 0; i < n; i++)
                    {
                            int temp = a;
                            a = b;
                            b = temp + b;
                    }
                    Console.WriteLine("ThreadId: {2}, fib({0}) = {1}", n, a, Thread.CurrentThread.GetHashCode());
                    return a;
            }
    }

    public class Task3Test : BaseTask
    {
            public void Run()
            {
                    bool listening = true;
                    long i = 0;
                    while (listening)
                    {
                            i++;

                            Func<int> fun = () => {
                                    int n = GetRandomInt(100);
                                    Fib f = new Fib();
                                    FibArgs args = new FibArgs();
                                    args.n = n;

                                    return f.Calculate(args);
                            };

                            var t = Task<int>.Factory.FromAsync(fun.BeginInvoke, fun.EndInvoke, null);
                            t.ContinueWith( x => { 
                                                    if (x.IsCompleted) {
                                                            x.Dispose();
                                                            x = null;
                                                    }
                                            }
                                    );
                    }
            }
    }

    public class Task4Test : BaseTask
    {
            public void Run()
            {
                    bool listening = true;
                    long i = 0;
                    while (listening)
                    {
                            int n = GetRandomInt(100);
                            Fib f = new Fib();
                            FibArgs args = new FibArgs();
                            args.n = n;

                            Task.Factory.StartNew(() => f.Calculate(args), TaskCreationOptions.LongRunning)
                                    .ContinueWith(x => {
                                            if(x.IsFaulted)
                                            { 
                                                    Console.WriteLine("OOPS, error!!!");
                                                    x.Exception.Handle(_ => true); //just an example, you'll want to handle properly

                                            }
                                            else if(x.IsCompleted)
                                            {
                                                    Console.WriteLine("Cleaning up task {0}", x.Id);
                                                    x.Dispose();
                                            }
                                    }
                            );
                    }
            }

    }
}

1 个答案:

答案 0 :(得分:0)

我很确定问题是你创建的任务比完成任务更快,所以他们排队。