Monotouch内存泄漏

时间:2012-07-22 01:17:53

标签: memory xamarin.ios memory-leaks

以下代码的变体用于工作,但现在我得到了内存泄漏,如下面的屏幕截图所示。我将代码从不同的线程移动到TimerElapsed事件(请参阅屏幕截图中的堆栈跟踪),对MD 3.0.3.4和MT 5.3.4进行了各种代码更新和升级。不幸的是,我似乎无法弄清楚为什么它不再起作用了。恢复到从常规线程调用它的代码的先前版本似乎也不起作用。这是当前版本的MD或MT中的错误吗?

正如你所看到的,我正在使用NSAutoReleasePool以及最后强制收集垃圾,但它仍然不起作用!

编辑:我在下面添加了代码,通过DrawCustomImage将声明中的unpackedImage跟踪,然后作为“imageToSet”参数进入SetImages(),然后作为“叠加”进入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;
    }

enter image description here

1 个答案:

答案 0 :(得分:0)

感谢您填写bug report

当您致电CGBitmapContextCreateImage(请参阅source)时,正在调用ToImage(来自乐器的堆栈跟踪)。该代码在5.2.12和5.3之间没有变化,所以它可能不是罪魁祸首。

托管 GCImage不会对句柄进行额外引用(。{中使用true)(请参阅source,最近没有更改任一)。

因此,这会将我们带到您从方法返回的unpackedImage UIImage。有一个更改(在5.3.x中),在此调用周围使用自动 NSAutoreleasePool

否则它最终会处理返回的unpackedImage的位置/方式(以及在哪个线程上,例如CoreGraphics是线程安全的,而UIKit 主要是不是)。

您可以在此处添加代码(此处或私下在错误报告中)吗?我不相信你的代码存在问题(因为它适用于5.2.x),但它会使跟踪变得更容易。

请注意,调用GC.Collect没有帮助(而且很少),因为您使用的实例都是IDisposable通常立即处置资源和删除完成步骤)并手动或使用using处理它们。