2017-04-26 22 views
1

我已經構建了一個應用程序,可以從USB驅動器讀取視頻文件並使用物理按鈕在它們之間切換。該應用程序運行良好一段時間,但一段時間後,該設備(DragonBoard 410c,最新的Windows Insider Preview Build 15051)崩潰,因爲應用程序已經使用了所有內存。內存泄漏在Windows IoT上播放視頻| UWP

查看設備入口中的進程,每次切換視頻文件時,「私人工作集」大致保持不變(大約30MB)時,可以看到「工作集」內存跳轉。

下面是如何加載視頻文件:

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的()在幾個地方手動,但沒有運氣。有任何想法嗎?

+0

只是一個快速的想法,但每個流都是一次性的,因此您應該在將'VideoVideo'設置爲流的新實例之後,將之前設置的流設置爲'VideoPlayer'的源, –

+0

調用流.Dispose();在VideoPlayer.SetSource()之後(這是發生內存尖峯的地方)沒有幫助。 – Thomas

+0

即使導航到不同的頁面也不會幫助釋放內存 – Thomas

回答

1

原來我的代碼畢竟是好的。我有一個Windows Update卡住/失敗了幾次,我沒有注意到。 當更新最終成功完成時,內存泄漏消失了。

1

既然你有一個StorageFile對象,我建議使用Source屬性和文件的Path代替SetSource,並手動打開Stream

此外,當您完成它時(最好在OnNavigatingFrom中完成),您應始終將MediaElement清空。

這裏是你的代碼,簡化:

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事件處理程序的視圖模型。

例如,如果您的視頻文件列表是字符串的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}"/> 

無需回元帥到UI線程:)

最後,你可以檢查出the demo here on GitHub,我已經實現SOMET與此類似。

+0

感謝您的詳細解答。這個問題實際上是由於缺少Windows更新引起的,但仍然很高興看到你應該怎麼做,我仍然會嘗試在我的代碼中包含這些最佳實踐。 – Thomas