【发布时间】:2013-01-05 22:35:36
【问题描述】:
我使用 EMGU+OpenCV 已经有一段时间了,遇到了这个AccessViolationException 的谜团。
首先,代码:
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;
}
}
代码很简单。分配一组图像。生成一个随机图像并用随机数填充它。对图像执行双边过滤。就是这样。
如果我在单个线程中执行此程序,(Threads=1) 一切似乎都可以正常工作,没有问题。 但是,如果我将并发线程数增加到 5,我会很快收到 AccessViolationException。
我检查了 OpenCV 代码并验证了 OpenCV 端没有分配,还检查了 EMGU 代码以搜索未固定的对象或其他问题,一切似乎都是正确的。
一些注意事项:
- 如果您删除
GC.Collect(),您会较少收到AccessViolationException,但它最终会发生。 - 只有在发布模式下执行时才会发生这种情况。在调试模式下,我没有遇到任何异常。
- 虽然每个 Image 是 675MB,但分配没有问题(我有 ALLOT 内存)并且会抛出“
OutOfMemoryException”以防系统内存不足。 - 我使用了双边过滤器,但其他过滤器/功能也出现此异常。
任何帮助将不胜感激。一个多星期以来,我一直在努力解决这个问题。
i7(无超频),Win7 64bit,32GB RAM,VS 2010,Framework 4.0,OpenCV 2.4.3
堆栈:
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 . . .
【问题讨论】:
-
异常发生时发布栈信息,
-
异常很明显。您正在尝试访问您的程序无法访问的内存(因为它没有填充它)。
-
我看不出有什么这么清楚。为什么在发布模式下会崩溃而不是在调试模式下?如果在单个线程中执行并在多个线程中崩溃,为什么它可以正常工作。请点亮我。
-
@Gilad 当尝试读取已处理的图像或多个线程共享相同的图像指针时,我通常会遇到此错误。不过,您的代码看起来很直接。
-
一段名为 XXXX 的代码中的 AccessViolationException 是(99% 的)XXXX 中的错误。您应该联系 Emgu.CV 的支持人员。这可能是因为你做了一些它不喜欢的事情,也许你可以找到解决方法,但这仍然是 Emgu.CV 中的一个错误。