异步任务内存泄漏

时间:2016-11-22 23:26:30

标签: c# asynchronous memory-leaks uwp

我只是在试图诊断观察到的内存泄漏的设备上运行UWP应用程序。

使用快照,我观察到我有越来越多的Task对象,这些对象似乎是从内部组件创建的,这会引发记录事件。

以下是比较快照和似乎泄漏的对象的屏幕截图。

Memory snapshot Path to root

我有两个绑定到OnLogReceived的事件监听器;它们看起来像这样:

ApplicationContext.Current.LoggerContext.OnLogReceived += LoggerContext_OnLogReceived;
ApplicationContext.Current.LoggerContext.OnLogReceived += (logLevel, timestamp, message) => RemoteLogHelper.SendMessage(logLevel, message);

这是第一个处理程序的定义。这将在屏幕上的滚动查看器中显示日志,并将条目截断为1000.LogEntryModel通过ViewModelBase实现INotifyPropertyChanged,以避免泄漏PropertyChanged。

private async void LoggerContext_OnLogReceived(LogLevel logLevel, DateTime timestamp, string message)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            var entry = new LogEntryModel
            {
                Message = string.Format("[{0:h:mm:ss tt}] {1}", timestamp, message)
            };
            entry.SetDispatcher(ApplicationContext.Current.Dispatcher);

            lock (ApplicationContext.Current.ReceiverDetails.Log)
            {
                ApplicationContext.Current.ReceiverDetails.Log.Add(entry);

                while (ApplicationContext.Current.ReceiverDetails.Log.Count > 1000)
                {
                    ApplicationContext.Current.ReceiverDetails.Log.RemoveAt(0);
                }
            }

            if (!uxPreventLogFromScrolling.IsChecked ?? false)
            {
                LogScrollViewer.ChangeView(0.0d, double.MaxValue, 1.0f);
            }
        });
    }

发送消息处理程序(2) 这会将日志行发送到远程API(如果为此设备启用了远程日志记录)以进行调试。我们希望这是火&忘了,这意味着我们不想等待日志成功发送到端点。

public static async void SendMessage(LogLevel logLevel, string message)
    {
        if (!IsEnabled())
            return;

        await Task.Run(() =>
        {
            try
            {
                ApplicationContext.Current.ApiClient.PostAsync<LogRequestModel, object>("/api/remote/receiver/log", new LogRequestModel { MacAddress = MacAddress, Text = message });
            }
            catch (Exception)
            {
                ; // we tried
            }
        });
    }

将此方法更改为以下定义不会更改行为(仍显示类似的快照结果)

public static async void SendMessage(LogLevel logLevel, string message)
    {
        if (!IsEnabled())
            return;

        try
        {
            await ApplicationContext.Current.ApiClient.PostAsync<LogRequestModel, object>("/api/remote/receiver/log", new LogRequestModel { MacAddress = MacAddress, Text = message });
        }
        catch (Exception)
        {
            ; // we tried
        }

    }

任何人都可以找出泄漏的原因以及我如何避免泄漏吗? 从研究来看,我认为我不需要处理任务,这里的所有内容看起来都应该在完成后自动清理。 但是我可以肯定地看到内存使用量在增长,而快照确认了这一点。

1 个答案:

答案 0 :(得分:1)

在此处记录答案,以防其他人遇到该问题。 我们使用.ContinueWith来防止任务泄漏

来源:http://stackoverflow.com/a/15524271/647728

    public static void SendMessage(LogLevel logLevel, string message)
    {
        if (!IsEnabled())
            return;

        //http://stackoverflow.com/a/15524271/647728
        ApplicationContext.Current.ApiClient.PostAsync<LogRequestModel, object>("/api/remote/receiver/log", new LogRequestModel { MacAddress = MacAddress, Text = message }).ContinueWith(t => { }, TaskContinuationOptions.OnlyOnFaulted);

    }

}