使用Mono Touch在循环中使用CGImage.ScreenImage时出现内存问题

我正在尝试创build一个应用程序来读取中兴的Monotouch和C#端口的QR码,但我正在处理内存问题。 当应用程序处理捕获的屏幕帧时,应用程序会收到内存警告,然后closures。 我已经删除了Zxing的调用,以追踪内存问题的源头,并可以通过捕获屏幕图像循环来重现问题。

这里是代码:

using System; using System.Drawing; using System.Collections.Generic; using System.Threading; using MonoTouch.UIKit; using MonoTouch.Foundation; using MonoTouch.CoreGraphics; using com.google.zxing; using com.google.zxing.common; using System.Collections; using MonoTouch.AudioToolbox; using iOS_Client.Utilities; namespace iOS_Client.Controllers { public class CameraOverLayView : UIView { private Thread _thread; private CameraViewController _parentViewController; private Hashtable hints; private static com.google.zxing.MultiFormatReader _multiFormatReader = null; private static RectangleF picFrame = new RectangleF(0, 146, 320, 157); private static UIImage _theScreenImage = null; public CameraOverLayView(CameraViewController parentController) : base() { Initialize(); _parentViewController = parentController; } private void Initialize() { } private bool Worker() { Result resultb = null; if(DeviceHardware.Version == DeviceHardware.HardwareVersion.iPhone4 || DeviceHardware.Version == DeviceHardware.HardwareVersion.iPhone4S) { picFrame = new RectangleF(0, 146*2, 320*2, 157*2); } if(hints==null) { var list = new ArrayList(); list.Add (com.google.zxing.BarcodeFormat.QR_CODE); hints = new Hashtable(); hints.Add(com.google.zxing.DecodeHintType.POSSIBLE_FORMATS, list); hints.Add (com.google.zxing.DecodeHintType.TRY_HARDER, true); } if(_multiFormatReader == null) { _multiFormatReader = new com.google.zxing.MultiFormatReader(); } using (var screenImage = CGImage.ScreenImage.WithImageInRect(picFrame)) { using (_theScreenImage = UIImage.FromImage(screenImage)) { Bitmap srcbitmap = new System.Drawing.Bitmap(_theScreenImage); LuminanceSource source = null; BinaryBitmap bitmap = null; try { source = new RGBLuminanceSource(srcbitmap, screenImage.Width, screenImage.Height); bitmap = new BinaryBitmap(new HybridBinarizer(source)); try { _multiFormatReader.Hints = hints; resultb = null; //_multiFormatReader.decodeWithState(bitmap); if(resultb != null && resultb.Text!=null) { InvokeOnMainThread( () => _parentViewController.BarCodeScanned(resultb)); } } catch (ReaderException re) { //continue; } } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { if(bitmap!=null) bitmap = null; if(source!=null) source = null; if(srcbitmap!=null) { srcbitmap.Dispose(); srcbitmap = null; } } } } return resultb != null; } public void StartWorker() { if(_thread==null) { _thread = new Thread(()=> { bool result = false; while (result == false) { result = Worker(); Thread.Sleep (67); } }); } _thread.Start(); } public void StopWorker() { if(_thread!=null) { _thread.Abort(); _thread = null; } //Just in case _multiFormatReader = null; hints = null; } protected override void Dispose(bool disposing) { StopWorker(); base.Dispose(disposing); } } } 

有趣的是,我看了一下http://blog.reinforce-lab.com/2010/02/monotouchvideocapturinghowto.html ,看看其他人是如何捕捉和处理video,这个代码和我的一样,在大约40秒记忆警告。

希望QR码能够在不到40秒的时间内被扫描,但是我不确定内存是否被释放,所以在扫描完许多代码之后,问题可能会出现。 无论哪种方式,应该有可能连续捕捉video饲料没有内存问题吗?

来自zxing.MonoTouch的原始System.Drawing.Bitmap由于缺lessDispose而使得它从不释放它分配的非托pipe内存。

最近的一个(从你的链接)确实释放了非托pipe内存,当Dispose被调用(更好)。 然而,它创build一个位图上下文(在它的构造函数),并不会手动处理(例如using )。 所以它依靠垃圾回收器(GC)稍后做…

在很多情况下,这不是一个大问题,因为GC最终将释放这个上下文实例并回收相关的内存。 但是如果你在循环中这么做的话,在GC启动之前你可能会用完(非托pipe)的内存。这会给你带来内存警告 ,iOS可能会决定杀死你的应用程序(或者它本身可能会崩溃) 。

但我不确定内存是否被释放

是的,它应该是 – 但也许不如你需要记忆回来那么快。 正确实施(并使用) IDisposable将解决此问题。

无论哪种方式,应该有可能连续捕捉video饲料没有记忆问题的权利?

是。 确保你尽快释放你的记忆,例如using (var ...) { } ,并确保你使用的第三方代码是一样的。

这有点违反直觉,但ScreenImage属性会在您每次调用它时创build一个新的CGImage实例,因此您也必须在该对象上调用Dispose:

 using (var img = CGImage.ScreenImage) { using (var screenImage = img.WithImageInRect(picFrame)) { } } 

我将只添加为我工作的实际解决scheme,它结合了以前答案的信息。 循环内的代码如下所示:

 using (var pool = new NSAutoreleasePool ()) { using (var img = CGImage.ScreenImage) { using (var screenImage = img.WithImageInRect(picFrame)) { using (_theScreenImage = UIImage.FromImage(screenImage)) { } } } } GC.Collect();