Исследование утечек памяти

Лучший инструмент для исследования утечек памяти в Windows IoT Core с помощью Visual Studio — это интегрированные средства диагностики.

Средства диагностики

Для приложений переднего плана можно следовать документации.

Однако эти средства не работают непосредственно с фоновым приложением Windows IoT Core. Одним из способов профилирования кода, используемого в фоновом приложении, является перенос его в приложение переднего плана для анализа:

  1. Добавление пустого приложения в решение фонового приложения
  2. Щелкните правой кнопкой мыши ссылки на пустое приложение и добавьте ссылку на фоновое приложение
  3. Измените метод Background App Run(), чтобы проверить, имеет ли параметр taskInstance значение NULL и обрабатывать эти случаи по-разному.
  4. Из вызова BlankApp BackgroundApp::Run(null)
  5. Установка точки останова для вызова BackgroundApp::Run
  6. При нажатии точки останова найдите окна "Средства диагностики" и нажмите кнопку ".
  7. Воспроизвести проблему
  8. Создание другого моментального снимка
  9. Используйте окно средств диагностики для диагностики утечки.

Создание тестового приложения

Начнем с приложения, которое выделяет память и не освобождает его для имитации утечки. Начните с создания нового фонового приложения C#: разработка фоновых приложений

Замените код в StartupTask.cs следующим кодом:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Windows.ApplicationModel.Background;
using Windows.System;

namespace LeakyBackgroundApp
{
    public sealed class StartupTask : IBackgroundTask
    {
        private Timer timer;
        private BackgroundTaskDeferral deferral;
        List<byte[]> buffer = new List<byte[]>();
        private const ulong minRemaining = 300 * 1024 * 1024;

        public void Run(IBackgroundTaskInstance taskInstance)
        {
            deferral = taskInstance.GetDeferral();
            timer = new Timer(Timer_Tick, null, 500, 500);
        }

        private void Timer_Tick(object state)
        {
            ulong remaining = (MemoryManager.AppMemoryUsageLimit - MemoryManager.AppMemoryUsage);
            ulong chunkSize = remaining / 100;

            try
            {
                if (remaining > minRemaining)
                {
                    var chunk = new byte[chunkSize];

                    // force virtual memory to be commited by writing to it
                    for (int i = 0; i < chunk.Length; i += 4096)
                    {
                        chunk[i] = 0xDA;
                    }

                    // "leak" memory by adding it to the list
                    buffer.Add(chunk);
                    Debug.WriteLine(String.Format("Allocated {0} chunk(s)", buffer.Count));
                }
                else
                {
                    timer.Change(Timeout.Infinite, Timeout.Infinite);
                }
            }
            catch (OutOfMemoryException ex)
            {
                Debug.Write(ex.Message);
                timer.Change(Timeout.Infinite, Timeout.Infinite);
            }
        }
    }
}

На этом этапе, если вы запускаете фоновое приложение на устройстве Интернета вещей, оно должно использовать много памяти и никогда не освобождать его. Если вы попытаетесь использовать средства диагностики на этом этапе, вы увидите то, что выглядит следующим образом, так как использование инструментов с фоновыми приложениями в настоящее время не поддерживается.

Фоновое приложение средств диагностики

Чтобы обойти эту проблему, мы добавим в решение приложение переднего плана. В Обозреватель решений щелкните правой кнопкой мыши папку решения и выберите Команду Add.New Project.

Добавление нового рисунка проекта 1

Выберите универсальное>приложение Visual C#>Windows в качестве типа проекта, присвойте проекту имя и нажмите кнопку "ОК".

Добавление нового рисунка проекта 2

Щелкните правой кнопкой мыши узел "Ссылки " нового проекта приложения переднего плана и выберите " Добавить ссылку".

Добавление нового рисунка проекта 3

В диалоговом окне диспетчера ссылок выберите "Проекты" на панели слева. В центральной области добавьте флажок рядом с проектом фонового приложения и нажмите кнопку "ОК".

Добавление нового рисунка проекта 4

Затем щелкните правой кнопкой мыши проект приложения переднего плана и выберите команду "Задать как начальный проект".

Добавление нового рисунка проекта 5

Добавьте код для создания экземпляра фонового объекта приложения и вызова run, передавающего значение NULL в качестве единственного параметра.

public MainPage()
{
    this.InitializeComponent();
    LeakyBackgroundApp.StartupTask task = new LeakyBackgroundApp.StartupTask();
    task.Run(null);
}

Затем в фоновом приложении проверьте метод Run, чтобы убедиться, что taskInstance не имеет значения NULL перед использованием.

public void Run(IBackgroundTaskInstance taskInstance)
{
    if (taskInstance != null)
    {
        deferral = taskInstance.GetDeferral();
    }

    timer = new Timer(Timer_Tick, null, 500, 500);
}
  1. Установите точку останова для вызова задачи. Run(null).

  2. Установите другую точку останова в таймере. Change(Timeout.Infinite, Timeout.Infinite) в Timer_Tick в StartupTask.cs.

  3. Нажмите клавишу F5, чтобы начать отладку

  4. При нажатии первой точки останова нажмите кнопку моментального снимка, чтобы задать базовый план для сравнения с

    Значок моментального снимка 1

  5. Нажатие клавиши F5

  6. При нажатии второй точки останова снова нажмите кнопку моментального снимка, чтобы записать текущее состояние.

Теперь средства диагностики должны отобразить график с увеличением использования памяти и двумя моментальными снимками следующим образом:

Средства диагностики с утечками

Посмотрите на строку 2 в столбце "Размер кучи". Щелкните второй номер со стрелкой плюса и стрелкой вверх. Отобразятся примерно следующие сведения:

Таблица моментальных снимков

Сортируйте по диффу по размеру, чтобы наибольшее число было вверху, а затем щелкните верхнюю строку. Над второй таблицей сведений щелкните "Ссылочные типы". Вторая таблица теперь должна отображать list<Byte[]> в качестве источника всего использования памяти.

Таблица моментальных снимков 1