访问冲突异常之谜 [英] Access Violation Exception mystery

查看:503
本文介绍了访问冲突异常之谜的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在EMGU + OpenCV的工作了一段时间,就遇到了这个 AccessViolationException 之谜。



第一件事,第一,代码:

 类AVE_Simulation 
{
公共静态INT宽度= 7500;
公共静态INT高度= 7500;
公共静态Emgu.CV.Image< RGB,浮动> []图像;

静态无效的主要(字串[] args)
{
INT N = 50;
INT线程= 5;

图像=新Emgu.CV.Image< RGB,浮动> [N];
Console.WriteLine(开始);

ParallelOptions PO =新ParallelOptions();
po.MaxDegreeOfParallelism =线程;
System.Threading.Tasks.Parallel.For(O,N,PO,新动作及所述; INT>((I)=>
{
图片[I] = GetRandomImage();
Console.WriteLine(Prossing形象:+ I);
图片[I] .SmoothBilatral(15,50,50);
所以GC.Collect();
} ));
Console.WriteLine(结束);
}

公共静态Emgu.CV.Image< RGB,浮> GetRandomImage()
{
Emgu.CV.Image< RGB,浮> IM =新Emgu.CV.Image< RGB,浮动>(宽度,高度);

浮动[,] D = im.Data;
随机R =新的随机((INT)DateTime.Now.Ticks);

为(INT Y = 0; Y<身高; Y ++)
{
的for(int x = 0; X<宽度; X ++)
{
D [Y,X,0] =(浮点)r.Next(255);
D [Y,X,1] =(浮点)r.Next(255);
D [Y,X,2] =(浮点)r.Next(255);
}
}
返回IM;
}

}



中的代码很简单。分配图像阵列。生成一个随机图像,并随机数填充它。在图像上执行双边滤波器。这就是它。



如果我在一个单独的线程执行这个程序,(线程= 1),似乎一切都没有问题,正常工作。
但是,如果我提出的并发线程数到5,我得到一个AccessViolationException非常快。



我已经去了OpenCV的代码,并证实有。关于OpenCV的一侧没有分配,也越过了EMGU代码搜索未固定的对象或其他问题,一切似乎是正确的。



一些注意事项:




  1. 如果您删除 GC.Collect的()您将获得 AccessViolationException 比较少,但它最终会发生。

  2. 当在Release模式下执行,这只是发生。在调试模式下我没有遇到任何异常。

  3. 虽然每个图像675MB没有与分配没有问题(我有记忆ALLOT)和 OutOfMemoryException异常'的情况下,系统内存不足异常。

  4. 我用双边滤波器,但我得到此异常与其他过滤器/功能,以及。



任何帮助,将不胜感激。我一直在试图解决这一问题的一个多星期。



i7处理器(没有超频),64位的Win7,32GB RAM,VS 2010,框架4.0,2.4 OpenCV的。 3



堆栈:

 开始
Prossing图像: 20
Prossing图片:30
Prossing图片:40
Prossing图片:0
Prossing图片:10
Prossing图片:21

未处理例外:System.AccessViolationException:尝试读取或写入受保护的内存。这通常是指示其他内存已损坏。
在Emgu.CV.CvInvoke.cvSmooth(IntPtr的SRC,DST的IntPtr,SMOOTH_TYPE类型的Int32参数1,参数2的Int32双参数3,双param4)
在TestMemoryViolationCrash.AVE_Simulation<主要> b__0(的Int32我)在C:\branches\1.1\TestMemoryViolationCrash\Program.cs:在System.Threading.Tasks.Parallel线32
<> c__DisplayClassf`1< ForWorker> b__c()。
。在System.Threading.Tasks.Task.InnerInvokeWithArg(任务childTask)所述
。在System.Threading.Tasks.Task&;方式> c__DisplayClass10&所述; ExecuteSelfReplicating> b__f(对象参数0)
在System.Threading.Tasks.Task.Execute()
在System.Threading.ExecutionContext.RunInternal(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态,布尔preserveSyncCtx)
在System.Threading.ExecutionContext.Run(的ExecutionContext ExecutionContext中,ContextCallback回调,对象状态,布尔preserveSyncCtx)
在System.Threading.Tasks.Task.ExecuteWithThreadLocal(任务&安培; currentTaskSlot)
在System.Threading.Tasks.Task.ExecuteEntry(布尔bPreventDoubleExecution)
。在System.Threading.Tasks.ThreadPoolTask​​Scheduler.TryExecuteTaskInline(任务任务,布尔taskWasPreviouslyQueued)
在System.Threading.Tasks.TaskScheduler.TryRunInline(任务任务,布尔taskWasPreviouslyQueued)
在的System.Threading。 Tasks.Task.InternalRunSynchronously(的TaskScheduler调度,布尔waitForCompletion)在System.Threading.Tasks.Parallel.ForWorker [TLocal](的Int32 fromInclusive,的Int32 toExclusive,parallelOptions parallelOptions,Action`1身体,Action`2 bodyWithState,Func键
`4 bodyWithLocal,Func`1禄
alInit,Action`1 localFinally)
在System.Threading.Tasks.Parallel.For(的Int32 fromInclusive,的Int32 toExclusive,parallelOptions parallelOptions,Action`1体)
在TestMemoryViolationCrash.AVE_Simulation.Main(字串[] args)在C:\branches\1.1\TestMemoryViolationCrash\Program.cs:行35

未处理的异常:System.AccessViolationException:尝试读取或写入受保护的内存。这通常是指示其他内存已损坏。
在Emgu.CV.CvInvoke.cvSmooth(IntPtr的SRC,DST的IntPtr,SMOOTH_TYPE类型的Int32参数1,参数2的Int32双参数3,双param4)
在TestMemoryViolationCrash.AVE_Simulation<主要> b__0(的Int32我)在C:\branches\1.1\TestMemoryViolationCrash\Program.cs:在System.Threading.Tasks.Parallel线32
<> c__DisplayClassf`1< ForWorker> b__c()。
。在System.Threading.Tasks.Task.InnerInvokeWithArg(任务childTask)所述
。在System.Threading.Tasks.Task&;方式> c__DisplayClass10&所述; ExecuteSelfReplicating> b__f(对象参数0)
在System.Threading.Tasks.Task.Execute()
在System.Threading.ExecutionContext.RunInternal(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态,布尔preserveSyncCtx)
在System.Threading.ExecutionContext.Run(的ExecutionContext ExecutionContext中,ContextCallback回调,对象状态,布尔preserveSyncCtx)
在System.Threading.Tasks.Task.ExecuteWithThreadLocal(任务&安培; currentTaskSlot)
在System.Threading.Tasks.Task.ExecuteEntry(布尔bPreventDoubleExecution)$在System.Threading.ThreadPoolWorkQueue.Dispatch b $ b()

未处理的异常:System.AccessViolationException:尝试读取或写入受保护的内存。这通常是指示其他内存已损坏。
在Emgu.CV.CvInvoke.cvSmooth(IntPtr的SRC,DST的IntPtr,SMOOTH_TYPE类型的Int32参数1,参数2的Int32双参数3,双param4)
在TestMemoryViolationCrash.AVE_Simulation<主要> b__0(的Int32我)在C:\branches\1.1\TestMemoryViolationCrash\Program.cs:在System.Threading.Tasks.Parallel线32
<> c__DisplayClassf`1< ForWorker> b__c()。
。在System.Threading.Tasks.Task.InnerInvokeWithArg(任务childTask)所述
。在System.Threading.Tasks.Task&;方式> c__DisplayClass10&所述; ExecuteSelfReplicating> b__f(对象参数0)
在System.Threading.Tasks.Task.Execute()
在System.Threading.ExecutionContext.RunInternal(ExecutionContext中的ExecutionContext,ContextCallback回调,对象状态,布尔preserveSyncCtx)
在System.Threading.ExecutionContext.Run(的ExecutionContext ExecutionContext中,ContextCallback回调,对象状态,布尔preserveSyncCtx)
在System.Threading.Tasks.Task.ExecuteWithThreadLocal(任务&安培; currentTaskSlot)
在System.Threading.Tasks.Task.ExecuteEntry(布尔bPreventDoubleExecution)$在System.Threading.ThreadPoolWorkQueue.Dispatch b $ b()
按任意键继续。 。 。


解决方案

您的例子不保持在参考结果图像的从Image.SmoothBilatral。输入图像的植根于静态数组等等都是精品。



这是Emgu.CV图像的数据数组被固定在实际图像内的GCHandle,这是从该映像包含数组和不妨碍收集的事实没有什么不同而的GCHandle的指针是由非托管代码(在一个管理的根到图像的abscence)使用。



由于该Image.SmoothBilatral方法不会做任何处理不是通过它的指针并返回它,我认为它被优化掉,以使结果图像可以同时流畅正在处理收集的程度等的临时结果图像。



因为没有终结这个类,OpenCV的将不会被要求释放它的非托管的映像头(其中有一个指向管理的图像数据)这样的OpenCV仍然认为它有一个可用的图像结构。



您可以通过采取参考SmoothBilatral的结果,并做一些与它(比如处理吧)修复它。



这扩展方法会同时工作(即允许它被successfuly呼吁标杆没有被使用的结果):

 公共静态类BilateralExtensionFix 
{
公共静态Emgu.CV.Image< testchannels,testtype> SmoothBilateral(这Emgu.CV.Image< testchannels,testtype>形象,诠释P1,P2 INT,INT P3)
{
VAR的结果= image.CopyBlank();
VAR手柄= GCHandle.Alloc(结果);
Emgu.CV.CvInvoke.cvSmooth(image.Ptr,result.Ptr,Emgu.CV.CvEnum.SMOOTH_TYPE.CV_BILATERAL,P1,P1,P2,P3);
handle.Free();
返回结果;
}
}



我觉得EmguCV应该做的是只钉住指针传递给OpenCV的同时使一个互操作调用。



PS OpenCV的双边过滤器崩溃(产生一个非常类似的错误,您的问题)与零通过任何类型的浮动图像变化(MIN()= MAX())在所有渠道。我想是因为它是如何构建它的分级EXP()查找表。

  //创建新的空白:



这可以被复制图像
变种zeroesF1 =新Emgu.CV.Image< RGB,浮动>(75,75);失败的
zeroesF1.Data
//取消注释下一行[0,0,0] + = 1.2037063600E-035f;
zeroesF1.SmoothBilatral(15,50,50);

这混淆了我,我其实有时候收到此错误是由于我的测试代码中的错误。 ..


I've been working with EMGU+OpenCV for quite some time and ran into this AccessViolationException mystery.

First thing first, the code:

class AVE_Simulation
    {
        public static int Width = 7500;
        public static int Height = 7500;
        public static Emgu.CV.Image<Rgb, float>[] Images;

        static void Main(string[] args)
        {
            int N = 50;
            int Threads = 5;

            Images = new Emgu.CV.Image<Rgb, float>[N];
            Console.WriteLine("Start");

            ParallelOptions po = new ParallelOptions();
            po.MaxDegreeOfParallelism = Threads;
            System.Threading.Tasks.Parallel.For(0, N, po, new Action<int>((i) =>
            {
                Images[i] = GetRandomImage();
                Console.WriteLine("Prossing image: " + i);
                Images[i].SmoothBilatral(15, 50, 50);
                GC.Collect();
            }));
            Console.WriteLine("End");
        }

        public static Emgu.CV.Image<Rgb, float> GetRandomImage()
        {
            Emgu.CV.Image<Rgb, float> im = new Emgu.CV.Image<Rgb, float>(Width, Height);

            float[, ,] d = im.Data;
            Random r = new Random((int)DateTime.Now.Ticks);

            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    d[y, x, 0] = (float)r.Next(255);
                    d[y, x, 1] = (float)r.Next(255);
                    d[y, x, 2] = (float)r.Next(255);
                }
            }
            return im;
        }

    }

The code is simple. Allocate an array of images. Generate a random image and populate it with random numbers. Execute bilateral filter over the image. That's it.

If I execute this program in a single thread, (Threads=1) everything seems to work normally with no problem. But, if I raise the number of concurrent threads to 5 I get an AccessViolationException very quickly.

I've went over OpenCV code and verified that there are no allocations on the OpenCV side and also went over the EMGU code searching for un-pinned objects or other problems and everything seems correct.

Some notes:

  1. If you remove the GC.Collect() you will get the AccessViolationException less often but it will eventually happen.
  2. This happens only when executed in Release mode. In Debug mode I didn't experience any exceptions.
  3. Although each Image is 675MB there is no problem with allocation (I have ALLOT of memory) and a 'OutOfMemoryException' is thrown in case the system ran out of memory.
  4. I used bilateral filter but I get this exception with other filters/functions as well.

Any help would be appreciated. I've been trying to fix this for more than a week.

i7 (no overclock), Win7 64bit, 32GB RAM, VS 2010, Framework 4.0, OpenCV 2.4.3

Stack:

Start
Prossing image: 20
Prossing image: 30
Prossing image: 40
Prossing image: 0
Prossing image: 10
Prossing image: 21

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Emgu.CV.CvInvoke.cvSmooth(IntPtr src, IntPtr dst, SMOOTH_TYPE type, Int32 param1, Int32 param2, Double param3, Double param4)
   at TestMemoryViolationCrash.AVE_Simulation.<Main>b__0(Int32 i) in C:\branches\1.1\TestMemoryViolationCrash\Program.cs:line 32
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass10.<ExecuteSelfReplicating>b__f(Object param0)
   at System.Threading.Tasks.Task.Execute()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
   at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
   at System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(Task task, Boolean taskWasPreviouslyQueued)
   at System.Threading.Tasks.TaskScheduler.TryRunInline(Task task, Boolean taskWasPreviouslyQueued)
   at System.Threading.Tasks.Task.InternalRunSynchronously(TaskScheduler scheduler, Boolean waitForCompletion)
   at System.Threading.Tasks.Parallel.ForWorker[TLocal](Int32 fromInclusive, Int32 toExclusive, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Func`4 bodyWithLocal, Func`1 loc
alInit, Action`1 localFinally)
   at System.Threading.Tasks.Parallel.For(Int32 fromInclusive, Int32 toExclusive, ParallelOptions parallelOptions, Action`1 body)
   at TestMemoryViolationCrash.AVE_Simulation.Main(String[] args) in C:\branches\1.1\TestMemoryViolationCrash\Program.cs:line 35

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Emgu.CV.CvInvoke.cvSmooth(IntPtr src, IntPtr dst, SMOOTH_TYPE type, Int32 param1, Int32 param2, Double param3, Double param4)
   at TestMemoryViolationCrash.AVE_Simulation.<Main>b__0(Int32 i) in C:\branches\1.1\TestMemoryViolationCrash\Program.cs:line 32
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass10.<ExecuteSelfReplicating>b__f(Object param0)
   at System.Threading.Tasks.Task.Execute()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
   at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Emgu.CV.CvInvoke.cvSmooth(IntPtr src, IntPtr dst, SMOOTH_TYPE type, Int32 param1, Int32 param2, Double param3, Double param4)
   at TestMemoryViolationCrash.AVE_Simulation.<Main>b__0(Int32 i) in C:\branches\1.1\TestMemoryViolationCrash\Program.cs:line 32
   at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
   at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
   at System.Threading.Tasks.Task.<>c__DisplayClass10.<ExecuteSelfReplicating>b__f(Object param0)
   at System.Threading.Tasks.Task.Execute()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
   at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
Press any key to continue . . .

解决方案

Your example doesn't keep a reference to the result image from Image.SmoothBilatral. The input images are rooted in a static array so are fine.

An Emgu.CV Image's data array is pinned to a GCHandle inside the actual image, this is no different from the fact that image contains the array and doesn't prevent collection while the GCHandle's pointer is in use by unmanaged code (in the abscence of a managed root to the image).

Because the Image.SmoothBilatral method doesn't do anything with its temporary result image other than pass its pointer and return it, I think it gets optimised away to the extent that the result image can be collected while the smooth is processing.

Because there's no finalizer for this class, opencv will not get called upon to release it's unmanaged image header (which has a pointer to the managed image data) so opencv still thinks it has a usable image structure.

You can fix it by taking a reference to the result of SmoothBilatral and doing something with it (like disposing it).

This extension method would also work (i.e. allow it to be called successfuly for benchmarking without the result being used):

public static class BilateralExtensionFix
{
    public static Emgu.CV.Image<testchannels, testtype> SmoothBilateral(this Emgu.CV.Image<testchannels, testtype> image, int p1, int p2 , int p3)
    {
        var result = image.CopyBlank();
        var handle = GCHandle.Alloc(result);
        Emgu.CV.CvInvoke.cvSmooth(image.Ptr, result.Ptr, Emgu.CV.CvEnum.SMOOTH_TYPE.CV_BILATERAL, p1, p1, p2, p3);
        handle.Free();
        return result;
    }
}

I think what EmguCV should be doing is only pinning pointers to pass to opencv while making an interop call.

p.s The OpenCv bilateral filter crashes (producing a very similar error to your problem) on any kind of float image passed with zero variation (min() = max()) across all channels. I think because of how it builds it's binned exp() lookup table.

This can be reproduced with:

    // create new blank image
    var zeroesF1 = new Emgu.CV.Image<Rgb, float>(75, 75);
    // uncomment next line for failure
    zeroesF1.Data[0, 0, 0] += 1.2037063600E-035f;
    zeroesF1.SmoothBilatral(15, 50, 50);

This was confusing me as I was actually sometimes getting this error due to a bug in my test code...

这篇关于访问冲突异常之谜的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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