简体   繁体   中英

Async task memory leak

I'm just profiling a UWP application running on a device trying to diagnose an observed memory leak.

Using snapshots, I've observed that I have a growing number of Task objects, which seem to be created from an internal component which raises logging events.

Here is a screenshot of a compared snapshot and the object that appears to be leaking.

内存快照 根目录

I have two event listeners bound to OnLogReceived; they look like this:

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

Here is the definition of first handler. This displays the log in a scrolling viewer on the screen and truncates the entries to 1000. The LogEntryModel implements INotifyPropertyChanged via ViewModelBase to avoid leaking 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);
            }
        });
    }

And the send message handler (2) This sends the log lines to a remote API (if remote logging is enabled for this device) for debugging purposes. We want this to be fire & forget, meaning we don't want to wait around for the log to be successfully sent to the endpoint.

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
            }
        });
    }

Changing this method to the following definition does not change the behavour (still showing a similar snapshot result)

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
        }

    }

Can anyone pinpoint why this is leaking and how I avoid it? From research, I don't think I need to dispose the tasks and everything here looks like it should be getting cleaned up automatically on completion. However I can definitly see the memory usage growing and the snapshots confirm this.

Documenting the answer here in case someone else runs into this. We used .ContinueWith to prevent leaking the task

Source: 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);

    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM