1

アニメーション GIF と、Silverlight で直接サポートされている画像を表示する必要がある WindowsPhone 7.8 アプリケーションがあります。public sealed partial class ExtendedImageControl : UserControl, IDisposableそのため、ImageSource という名前の DependancyProperty を持つカスタム ユーザー コントロールを作成しました。このプロパティは URL にバインドされています。コード ビハインドは、通常の Image コントロールを LayoutRoot に挿入するか、AnimatedImage を挿入します。ただし、AnimatedImage が表示されなくなったり、含まれているページが閉じられたりしても、メモリは解放されません。

読み込みロジックは次のとおりです。

ExtendedImage loadedImage = (ExtendedImage)await Utils.Caching.Image.LoadCachedImageFromUrlAsync<ExtendedImage>(loadedLocation);

                        if (ImageSource == loadedLocation)
                        {
                            AnimatedImage image = new AnimatedImage();
                            image.Stretch = stretch;
                            image.Source = loadedImage;
                            LayoutRoot.Children.Add(image);
                            CurrentImageMode = ExtendedImageMode.AnimatedImage;
                            loadedImage = null;
#if DEBUG
                            App.logger.log("Loaded {0} as animated image", loadedLocation);
#endif
                            imageDisplay = image;
                            raiseImageUpdated();
                        }

最終的に、画像は次のようにロードされます

        WebClient client = new WebClient();
        ExtendedImage image = new ExtendedImage();
        using (Stream source = await client.OpenReadTaskAsync(location))
        {

            if (location.ToString().EndsWith("gif", StringComparison.InvariantCultureIgnoreCase))
            {
                image.SetSource(source);

                TaskCompletionSource<ExtendedImage> imageLoaded = new TaskCompletionSource<ExtendedImage>();

                EventHandler loadingCompleteHandler = new EventHandler((sender, e) =>
                {
                    imageLoaded.SetResult(image);
                });

                EventHandler<UnhandledExceptionEventArgs> loadingFailedHandler = new EventHandler<UnhandledExceptionEventArgs>((sender, e) =>
                {
                    imageLoaded.SetResult(image);
#if DEBUG
                    if (System.Diagnostics.Debugger.IsAttached)
                        System.Diagnostics.Debugger.Break();
#endif
                });



                image.LoadingCompleted += loadingCompleteHandler;
                image.LoadingFailed += loadingFailedHandler;

                image = await imageLoaded.Task;

                //Remove handlers, otherwise the object might be kept in the memory
                image.LoadingCompleted -= loadingCompleteHandler;
                image.LoadingFailed -= loadingFailedHandler;
            }
            else
            {
                //... load with native Silverlight methods
            }
        }

        return image;

非常に早い段階でメモリの問題に気付いたので、コントロールは IDisposable インターフェイスを実装します。

    public void Dispose()
    {
        unloadImage();
        GC.SuppressFinalize(this);
    }

    private void unloadImage()
    {
        SmartDispatcher.BeginInvoke(() =>
        {
            if (imageDisplay != null)
            {
                if (imageDisplay is AnimatedImage)
                {
                    if ((imageDisplay as AnimatedImage).Source != null & (imageDisplay as AnimatedImage).Source.Frames != null)
                        (imageDisplay as AnimatedImage).Source.Frames.Clear();

                    (imageDisplay as AnimatedImage).Stop();

                    (imageDisplay as AnimatedImage).Source = null;
                }
                else if (imageDisplay is Image && ((Image)imageDisplay).Source != GIFplaceholder)
                {
                    (imageDisplay as Image).Source = null;
                }

                imageDisplay = null;
            }
        });
    }

ただし、画像に対して Dispose メソッドが呼び出されることはありません。

このオブジェクトが GC によって検出されない理由を調べるにはどうすればよいですか? 私が理解している限り、イベントハンドラーを登録していません。アプリケーションページから離れたときに収集する必要があります。デストラクタも追加しようとしましたが、これも呼び出されません。

4

3 に答える 3

1

メモリ リークは ImageTools にはありませんが、実際には Silverlight ランタイムのバグです。

イメージを動的に追加および削除するとメモリ リークが発生する

回避策: BitmapImages をアプリケーションに動的に追加または削除する (つまり、ツリーからの追加/削除) 場合、ツリーから Image 要素を削除する前に、Image.Source = null を設定する必要があります。これにより、BitmapImage がガベージ コレクションの対象になります。バグの状態: アクティブなバグ。*

参考文献:

Silverlight:メモリからイメージをアンロード (破棄) する方法は? https://blogs.msdn.microsoft.com/silverlight_sdk/2008/10/28/silverlight-bugs-and-workarounds/

XAML ページから移動する前に各 ExtendedImage を Nothing に設定すると、アプリケーションのメモリ使用量が大幅に削減されることがすぐに確認できます。

これらのリークを追跡するために、App.xaml の RootFrame_Navigating イベントに以下を追加します。

Dim applicationCurrentMemoryUsage As Long = Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage")
Dim applicationPeakMemoryUsage As Long = Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage")
Debug.WriteLine(DateTime.Now.ToLongTimeString() & " Current : " & applicationCurrentMemoryUsage & "  Peak : " & applicationPeakMemoryUsage)
于 2016-06-17T23:27:00.370 に答える
0

アプリケーションページが別の場所に移動したときに収集する必要があります

ナビゲーション プロセスにコードを挿入して、実際に dispose を呼び出し、ページから画像のリンクを解除します。画像を保持しているものはすべて破棄されない可能性があるため、画像が破棄されることはありません。手でそれを行い、同じことが起こっているかどうかを確認してください。


OPは、アニメーション画像に関する何かがまだ懸念事項であると報告しました. pinningメモリへのイメージのサブスクリプションがないことを確認してください。すべてのサブスクリプションは、サブスクリプション解除プロセスで削除する必要があり-=ます。それ以外の場合、オブジェクトへの参照がなくても、サブスクリプションはそれをメモリにピン留めし、生きたままにします。

于 2013-09-11T17:55:47.900 に答える
-1

誰かがこれに出くわしたら...

解決方法はこちらをご覧ください。

簡単な答え: 移動する前に AnimatedImage で Stop() を呼び出します。

編集: コントロールがページから削除されたときにアニメーションを自動的に停止するようにライブラリを更新しました。ソースの最新バージョンをダウンロードしてビルドします。

于 2013-11-21T01:02:59.320 に答える