1

以下のコードのバリエーションは以前は機能していましたが、以下のスクリーンショットでわかるように、メモリリークが発生します。コードを別のスレッドからTimerElapsedイベントに移動し(スクリーンショットのスタックトレースを参照)、さまざまなコードの更新とMD3.0.3.4およびMT5.3.4へのアップグレードを行いました。残念ながら、なぜそれが機能しなくなったのか理解できないようです。通常のスレッドから呼び出されている以前のバージョンのコードに戻すことも機能しないようです。これは、MDまたはMTの現在のバージョンのバグですか?

ご覧のとおり、NSAutoReleasePoolを使用しているだけでなく、最後にガベージコレクションを強制していますが、それでも機能しません。

編集:以下に、unpackedImageを宣言からDrawCustomImageを介してトレースし、次に「imageToSet」パラメーターとしてSetImages()に、次に「overlay」パラメーターとしてoverlayImage()にトレースするコードを追加しました。SetImageは、メインスレッドでその中のコードを呼び出します。これは、最終的にUpdateLiveScreenを呼び出すと(結果のoverlayedImageを使用して)、実際に画面に描画されるためです。

    static UIImage unpackedImage = new UIImage();

    public static void DrawCustomImage(IntPtr buffer, int width, int height, int bytesPerRow, CGColorSpace colSpace, byte[] rawPixels, ref UIImage unpackedImage)
    {
        using (var pool = new NSAutoreleasePool())
        {
            GCHandle pinnedArray = GCHandle.Alloc(rawPixels, GCHandleType.Pinned);
            IntPtr pointer = pinnedArray.AddrOfPinnedObject();

            // Set a grayscale drawing context using the image buffer
            CGBitmapContext context = new CGBitmapContext(pointer, width, height, 8, bytesPerRow, colSpace, CGImageAlphaInfo.None);

            try
            {
                // Convert the drawing context to an image and set it as the unpacked image
                //using (var pool = new NSAutoreleasePool())
                {
                    using (var img = context.ToImage())
                    {
                        unpackedImage = UIImage.FromImage(img);
                    }
                }
            } finally
            {
                pinnedArray.Free();
                if (context != null)
                    context.Dispose();
            }
        }
        GC.Collect();
    }

    SetImages(labelText, symbolArray[0], unpackedImage, points);

    public static void SetImages(String labelText, UIImage symbol, UIImage imageToSet, PointF[] points)
    {
        appReference.InvokeOnMainThread(delegate
        {
            int imageWidth = 716;
            int imageHeight = (int)imageToSet.Size.Height;
                            int nextFreeMainImageColumn = 5; // This gets set dynamically, but is simplified here for readability 

            lock (displayLocker)
            {
                // Get the current doppler image
                UIImage mainImage = GetMainImage();

                // Add the new imageToSet to the current image by overlaying it adjacent to the current image
                UIImage overlayedImage = overlayImage(mainImage, imageToSet,
                                     new RectangleF(0, 0, imageWidth, imageHeight),
                                     new RectangleF(nextFreeMainImageColumn, 0, imageToSet.Size.Width, imageHeight));

                // Update the live screen with the updated image and frame number
                LiveCont.UpdateLiveScreen(labelText, symbol, overlayedImage, points);
            }
        });
    }

    public static UIImage overlayImage(UIImage image, UIImage overlay, RectangleF imageBoundingBox, RectangleF overlayBoundingBox)
    {
        int numBytes = 4;   // Four bytes per pixel for a color image (Alpha, Red, Green, Blue)
        int bytesPerRow = (int)imageBoundingBox.Width * numBytes;

        // Set a color drawing context
        CGBitmapContext context = new CGBitmapContext(
            IntPtr.Zero,
            (int)imageBoundingBox.Width,
            (int)imageBoundingBox.Height,
            8,
            bytesPerRow,
            CGColorSpace.CreateDeviceRGB(),
            CGImageAlphaInfo.NoneSkipFirst
        );

        UIImage overlayedImage = null;
        try
        {
            context.DrawImage(imageBoundingBox, image.CGImage);             // Draw the main image
            context.DrawImage(overlayBoundingBox, overlay.CGImage);         // Draw the overlay

            using (var img = context.ToImage())
            {
                overlayedImage = UIImage.FromImage(img);                    // Convert the context back to an image
            }
        }
        finally
        {
            if (context != null)
                context.Dispose();
            image.Dispose();
        }

        return overlayedImage;
    }

ここに画像の説明を入力してください

4

1 に答える 1

0

バグレポートにご記入いただきありがとうございます。

CGBitmapContextCreateImage(Instrumentsのスタックトレースからの)へのネイティブ呼び出しは、呼び出し時に実行されますToImageソースを参照)。そのコードは5.2.12と5.3の間で変更されていないため、原因ではない可能性があります。

管理対象 は、ハンドル( .ctorで使用されます)GCImageへの追加の参照を取りません(ソースを参照してください。最近の変更もありません)。true

だから、これはunpackedImage UIImageあなたがあなたのメソッドから戻ることに私たちを連れて行きます。この呼び出しの前後で自動 が使用される変更(5.3.x)があります。NSAutoreleasePool

そうでなければ、それはあなたが返されたものをどこで/どのように扱うかで終わりますunpackedImage(そしてどのスレッドで、例えばCoreGraphicsはスレッドセーフですが、UIKitはほとんどそうではありません)。

これを示すコード(ここまたはバグレポートに非公開で)を追加できますか?コードに問題があるとは思いませんが(5.2.xで動作するため)、これを追跡するのがはるかに簡単になります。

使用しているインスタンスはすべて実装され(通常はすぐにリソースを破棄し、ファイナライズステップを削除します)、手動またはで破棄するため、呼び出しGC.Collectは役に立ちません(ほとんどありません) 。IDisposableusing

于 2012-07-22T15:18:09.967 に答える