使用Mono Touch循环使用CGImage.ScreenImage时出现内存问题 [英] Memory issue when using CGImage.ScreenImage in a loop using Mono Touch

查看:79
本文介绍了使用Mono Touch循环使用CGImage.ScreenImage时出现内存问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个应用程序以使用Monotouch和Zxing的C#端口读取QR码,但遇到内存问题.当应用程序处理捕获的屏幕帧时,该应用程序会收到内存警告,然后关闭.我已经删除了对Zxing的调用,以跟踪内存问题的根源,并且只需在循环中捕获屏幕图像即可重现该问题.

I'm trying to create an app to read QR codes using Monotouch and C# port of Zxing but I'm hitting memory issues. While the app processes captured screen frames the app receives memory warnings and is then shut down. I have removed the call to Zxing to track down where the memory issue stems from and can reproduce the issue with just capturing the screen image in a loop.

这是代码:

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 来尝试看看其他人如何捕获和处理视频,并且此代码与我的代码一样受苦,大约40秒后由于内存警告而退出.

Interestingly I took a look at http://blog.reinforce-lab.com/2010/02/monotouchvideocapturinghowto.html to try and see how others were capturing and processing video and this code suffers from the same as mine, quitting after about 40 seconds with memory warnings.

希望QR码将在不到40秒的时间内被扫描,但是我不确定是否释放了内存,因此在扫描了许多代码后问题可能会出现.无论哪种方式,都应该可以连续捕获视频,而不会出现内存问题,对吗?

Hopefully the QR codes will be scanned in less than 40 seconds but I'm not sure if the memory ever gets released so the problem may crop up after many codes have been scanned. Either way it should be possible to capture a video feed continuously without memory issues right?

推荐答案

zxing.MonoTouch的原始System.Drawing.Bitmap缺少Dispose,这使得它从不释放分配的非托管内存.

The original System.Drawing.Bitmap from zxing.MonoTouch suffered from a lack of Dispose which made it never release the unmanaged memory it allocated.

最近的一个(从您的链接中获取)在调用Dispose时会释放非托管内存(最好).但是,它会创建一个位图上下文(在其构造函数中),并且不会手动对其进行处理(例如,使用using).因此,它依赖垃圾收集器(GC)稍后进行处理...

The more recent one (from your link) does free the unmanaged memory when Dispose is called (it's better). However it creates a bitmap context (in it's constructor) and does not dispose it manually (e.g. with a using). So it relies on the garbage collector (GC) to do it later...

在许多情况下,这并不是一个大问题,因为GC最终将释放此上下文实例并回收关联的内存.但是如果您要循环执行此操作,则有可能在GC启动之前耗尽(非托管)内存.这将为您提供内存警告和iOS可以决定终止您的应用程序(否则它本身可能会崩溃).

In many cases this is not a big issue since the GC will, eventually, free this context instance and will reclaim the associated memory. However if you're doing this in a loop it's possible you'll run out of (unmanaged) memory before the GC kicks in. That will get you memory warnings and iOS can decide to kill your application (or it could crash by itself).

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

but I'm not sure if the memory ever gets released

是的,应该是-但可能不如需要的内存恢复那么快.正确实施(和使用)IDisposable将解决此问题.

Yes, it should be - but maybe not as fast as you need the memory back. Implementing (and using) IDisposable correctly will solve this.

无论哪种方式,都应该可以连续捕获视频,而不会出现内存问题对吗?

Either way it should be possible to capture a video feed continuously without memory issues right?

是的.确保尽快释放内存,例如using (var ...) { },并确保您使用的第三方代码也是如此.

Yes. Make sure you're releasing your memory as soon as possible, e.g. with using (var ...) { }, and ensure the 3rd party code you use does the same.

这篇关于使用Mono Touch循环使用CGImage.ScreenImage时出现内存问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆