Утечка памяти при воспроизведении видео на Windows IoT | UWP

Я создал приложение, которое может читать видеофайлы с USB-накопителя и переключаться между ними с помощью физических кнопок. Некоторое время приложение работает хорошо, но через некоторое время устройство (DragonBoard 410c, последняя версия Windows Insider Preview Build 15051) дает сбой из-за того, что приложение использует всю память.

Просматривая процессы на портале устройства, я вижу скачок памяти "Рабочий набор" каждый раз, когда переключаю видеофайл, в то время как "Частный рабочий набор" примерно не меняется (около 30 МБ).

Вот как я загружаю видеофайл:

C#

private IReadOnlyList<StorageFile> _videofiles

// list all available video files
public void Init(){
    var queryOptions = new QueryOptions();
    queryOptions.FolderDepth = depth;
    foreach (var fileType in fileTypes)
    {
        queryOptions.FileTypeFilter.Add(fileType);
    }

    var query = KnownFolders.RemovableDevices.CreateFileQueryWithOptions(queryOptions);
    _videofiles = await query.GetFilesAsync();
}

private async void SelectVideo(int videoId)
{         
    StorageFile videofile = _videofiles.Where(x => x.DisplayName == videoId.ToString()).FirstOrDefault();
    if (videofile != null)
    {
        Debug.WriteLine($"Video {videofile.DisplayName} was selected");
        var stream = await videofile.OpenAsync(FileAccessMode.Read);
        VideoPlayer.SetSource(stream, videofile.FileType);
    }
}

// since the button interrupt is not on the UI thread, SelectVideo() is called like this
private async void SelectVideoMarshalled(int videoId)
{
    await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
    () =>
    {
        SelectVideo(videoId);
    });
}

XAML

<ContentControl x:Name="VideoPlayer" Content="{x:Bind ViewModel.VideoPlayer, Mode=OneWay}"/>

Я попытался запустить GC.Collect() вручную в нескольких местах, но пока не повезло. Есть идеи?

2 ответа

Решение

Оказывается, мой код был в порядке в конце концов. У меня было несколько раз зависание / сбой Windows Update, которого я не заметил. После успешного завершения обновления утечки памяти исчезли.

Так как у вас есть StorageFile объект, я рекомендую использовать Source свойство и файл Path вместо SetSource и открытие Stream вручную.

Кроме того, вы всегда должны обнулять MediaElement, когда вы закончите с ним (лучше всего это делать в OnNavigatingFrom).

Вот ваш код, упрощенный:

private void SelectVideo(string videoId)
{
    var videofile = _videofiles.FirstOrDefault(x => x.DisplayName == videoId.ToString());
    if (videofile == null) return;

    Debug.WriteLine($"Video {videofile.DisplayName} was selected");

    VideoPlayer.Source = new Uri(videofile.Path);
}


protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    VideoPlayer.Stop();
    VideoPlayer.Source = null;

    base.OnNavigatedFrom(e);
}

У меня также есть побочный комментарий, вы можете x:Bind обработчики событий для ViewModel.

Например, если ваш список видеофайлов ListView строки:

public void VideosListView_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e?.AddedItems?.Count > 0)
    {
        var fileDisplayName = e.AddedItems.FirstOrDefault() as string;
        if (!string.IsNullOrEmpty(fileDisplayName))
            SelectVideo(fileDisplayName);
    }
}

Обратите внимание, что мне нужно только изменить сигнатуру метода на public а затем в XAML вы можете сделать это:

<ListView ItemsSource="{x:Bind ViewModel.VideoFiles, Mode=OneTime}"
          SelectionChanged="{x:Bind ViewModel.VideosListView_OnSelectionChanged}"/>

Нет необходимости маршалировать обратно в пользовательский интерфейс:)

Наконец, вы можете проверить демо здесь на GitHub, где я реализовал нечто похожее на это.

Другие вопросы по тегам