编辑:添加了代码( 095行的异常,第5次命中)。
public DataTable ParseBarcodes(String[] files, BarcodeZoneScan[] scanParameters)
{
message = null;
//gmseBitmap img = null;
gmseBitmap rotImg = null;
gmseBitmap parseImage = null;
gmseBitmap tempImage = null;
DataTable codes = new DataTable();
codes.Columns.Add("PageNumber");
codes.Columns.Add("Text");
codes.Columns.Add("Type");
codes.Columns.Add("RegionName");
try
{
gmseBarcodeInfoCollection bcc;
gmseBarcodeReaderParameter param = new gmseBarcodeReaderParameter();
gmseLicense.License = "plaintext license key ommited";
String dvImageName;
int searchCount = 0;
for (int dvCount = 0; dvCount < files.Length; dvCount++)
{
if (cancelled) //If cancelled, end the loops
{
dvCount = files.Length;
break;
}
dvImageName = files[dvCount].ToString();
using (gmseBitmap img = new gmseBitmap(dvImageName))
{
int framecount = img.GetFrameCount();
for (int e = 0; e < framecount; e++)
{
for (int j = 0; j < scanParameters.Length; j++)
{
if (scanParameters[j].Range == PageRange.All ||//All
(scanParameters[j].Range == PageRange.Even && (searchCount == 0 || searchCount % 2 == 0)) || //even
(scanParameters[j].Range == PageRange.Odd && (searchCount != 0 && searchCount % 2 != 0)) ||
(scanParameters[j].Range == PageRange.First && searchCount == 0))
{
//Setup what barcodes are going to be search for
param.BarcodeType = 0;
if (scanParameters[j].BarcodeTypes == BarcodeType.All) //All
{
param.BarcodeType = (int)gmseBarcodeType.All;
}
else
{
if ((scanParameters[j].BarcodeTypes & BarcodeType.Code39) != 0) //Code 39
param.BarcodeType = param.BarcodeType | (int)gmseBarcodeType.Code39;
if ((scanParameters[j].BarcodeTypes & BarcodeType.Code11) != 0) //Code 11
param.BarcodeType = param.BarcodeType | (int)gmseBarcodeType.Code11;
if ((scanParameters[j].BarcodeTypes & BarcodeType.Code93) != 0) //Code 93
param.BarcodeType = param.BarcodeType | (int)gmseBarcodeType.Code93;
if ((scanParameters[j].BarcodeTypes & BarcodeType.Code128) != 0) //Code 128
param.BarcodeType = param.BarcodeType | (int)gmseBarcodeType.Code128;
if ((scanParameters[j].BarcodeTypes & BarcodeType.Ean8) != 0) //EAN 8
param.BarcodeType = param.BarcodeType | (int)gmseBarcodeType.EAN8;
if ((scanParameters[j].BarcodeTypes & BarcodeType.Ean13) != 0) // EAN 13
param.BarcodeType = param.BarcodeType | (int)gmseBarcodeType.EAN13;
if ((scanParameters[j].BarcodeTypes & BarcodeType.I2of5) != 0) //I2of5
param.BarcodeType = param.BarcodeType | (int)gmseBarcodeType.i2of5;
}
param.IgnoreCheckSum = 1;
param.ReadMode = gmseBarcodeReadMode.WholeBitmap;
using (rotImg = new gmseBitmap(img.ExtractFrame(e)))
{
// do some basic image enhancement for better results
rotImg.ChangePixelFormat(System.Drawing.Imaging.PixelFormat.Format32bppArgb);
rotImg.SelectActiveFrame(e);
if (scanParameters[j].WholePage)
{
parseImage = rotImg.ExtractFrame(e);
}
else
{
using (tempImage = rotImg.ExtractFrame(e))
{
Rectangle convertedRect = returnConvertedRectangle(tempImage, scanParameters[j].Dimensions);
if (convertedRect.IntersectsWith(new Rectangle(0, 0, tempImage.Width, tempImage.Height)))
{
//GC.Collect(); //Test so I can see what objects are still alive in dump
parseImage = tempImage.CopyRectangle(convertedRect); //Exception here
}
}
}
}
//rotImg.Dispose();
//rotImg = null;
if (parseImage != null)
{
//Now we will apply the image enhancements:
if (scanParameters[j].Enhancements != ImageEnhancement.None)
{
rotImg = EnhanceImage(parseImage, scanParameters[j].Enhancements);
parseImage.Dispose();
parseImage = null;
}
if ((scanParameters[j].BarcodeScanDirection & ScanDirection.LeftToRight) != 0 && !cancelled)
{
if (parseImage == null)
{
tempImage = new gmseBitmap(rotImg.Image, 1);
}
else
{
tempImage = new gmseBitmap(parseImage.Image, 1);
}
bcc = tempImage.ReadBarcodes(param);
foreach (gmseBarcodeInfo bc in bcc)
{
addBarcode(codes, new object[] { searchCount, bc.Text, gmseBarcodeTypeConvert(bc.BarcodeType), scanParameters[j].ZoneName });
}
tempImage.Dispose();
tempImage = null;
}
if ((scanParameters[j].BarcodeScanDirection & ScanDirection.RightToLeft) != 0 && !cancelled)
{
if (parseImage == null)
{
tempImage = new gmseBitmap(rotImg.Image, 1);
}
else
{
tempImage = new gmseBitmap(parseImage.Image, 1);
}
tempImage.RotateFlip(RotateFlipType.Rotate180FlipNone);
bcc = tempImage.ReadBarcodes(param);
foreach (gmseBarcodeInfo bc in bcc)
{
addBarcode(codes, new object[] { searchCount, bc.Text, gmseBarcodeTypeConvert(bc.BarcodeType), scanParameters[j].ZoneName });
}
tempImage.Dispose();
tempImage = null;
}
if ((scanParameters[j].BarcodeScanDirection & ScanDirection.TopToBottom) != 0 && !cancelled)
{
if (parseImage == null)
{
tempImage = new gmseBitmap(rotImg.Image, 1);
}
else
{
tempImage = new gmseBitmap(parseImage.Image, 1);
}
tempImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
bcc = tempImage.ReadBarcodes(param);
foreach (gmseBarcodeInfo bc in bcc)
{
addBarcode(codes, new object[] { searchCount, bc.Text, gmseBarcodeTypeConvert(bc.BarcodeType), scanParameters[j].ZoneName });
}
tempImage.Dispose();
tempImage = null;
}
if ((scanParameters[j].BarcodeScanDirection & ScanDirection.BottomToTop) != 0 && !cancelled)
{
if (parseImage == null)
{
tempImage = new gmseBitmap(rotImg.Image, 1);
}
else
{
tempImage = new gmseBitmap(parseImage.Image, 1);
}
tempImage.RotateFlip(RotateFlipType.Rotate270FlipNone);
bcc = tempImage.ReadBarcodes(param);
foreach (gmseBarcodeInfo bc in bcc)
{
addBarcode(codes, new object[] { searchCount, bc.Text, gmseBarcodeTypeConvert(bc.BarcodeType), scanParameters[j].ZoneName });
}
tempImage.Dispose();
tempImage = null;
}
if (parseImage != null)
{
parseImage.Dispose();
parseImage = null;
}
if (rotImg != null)
{
rotImg.Dispose();
rotImg = null;
}
}
}
}
searchCount++;
if (cancelled) //If cancelled, end the loops
{
e = framecount;
dvCount = files.Length;
}
}
} //end using img
//img.Dispose();
//img = null;
}
}
catch (Exception ex)
{
message = ex.Message;
}
finally
{
if (img != null)
{
img.Dispose();
img = null;
}
if (rotImg != null)
{
rotImg.Dispose();
rotImg = null;
}
if (tempImage != null)
{
tempImage.Dispose();
tempImage = null;
}
if (parseImage != null)
{
parseImage.Dispose();
parseImage = null;
}
}
if (!String.IsNullOrEmpty(message))
throw new Exception(message);
return codes;
}我们使用这个GMSE成像插件来帮助OCR读取扫描条形码,它通过旋转图像10度来处理倾斜,直到读取为止。发现了一个错误,在那里扫描不同大小的工作表会引发错误。
我把它从主程序追踪到我们的一个DLL,在那里我发现它正在捕获一个OutOfMemoryException。
最初的TIF是300 of,但有相当数量的复制,以旋转图像。(在4个位图之间)但是,我一直在跟踪程序并监视局部变量,似乎在故障循环的方法之前,每个位图都被正确地处理和分配为null。
我还尝试在循环结束时添加GC.Collect()。
我是在一台32位的W7机器上,我读过它的每个对象都有2GB的限制,有大量的内存,所以这一点都不缺。一直在Task上观看,我的RAM使用量从1.72GB增加到1.78GB。
这是一个棘手的问题,因为OoM似乎是一个异常发生的错误。我想知道有没有人在处理这种例外的问题上有什么建议?我不是Visual的主人,有没有一种监视资源/内存使用情况的简单方法?
或者知道我能用什么工具来帮助你?
在这里转储错误消息,不确定在这种情况下代码段有多有用.
System.OutOfMemoryException was caught
Message=Out of memory.
Source=System.Drawing
StackTrace:
at System.Drawing.Bitmap.Clone(Rectangle rect, PixelFormat format)
at gmse.Imaging.gmseBitmap.CopyRectangle(Rectangle r)
at ImagingInterface.ImagingFunctions.ParseBarcodes(String[] files, BarcodeZoneScan[] scanParameters) in C:\Working\Scan.backup\Global Dlls\v2.6.0.02\ScanGlobalDlls\ImagingInterface\ImagingFunctions.cs:line 632InnerException:
(目前正在更多地阅读GC/内存管理http://msdn.microsoft.com/en-us/library/ee851764.aspx )
在本指南的步骤上工作,在直接窗口中使用SOS调试器,目的是精确指出异常是由托管代码还是非托管代码生成的。
上面的步骤显示了托管代码的问题,因为它显示了SOS的异常类型。
Exception object: 39594518
Exception type: System.OutOfMemoryException
Message: <none>
InnerException: <none>
StackTrace (generated):我拿走的垃圾堆似乎并不像我所期望的那样是成千上万的位图。不是100%确定如何解释转储,所以看看我能在它上找到什么。
不知道现在该搬到哪里去!(搜查.)
编辑:
我一直在尝试把这个博客中的经验运用到我的问题上。
从PerfMon开始

这个图表显示了我的程序从执行到它捕获异常的位置。
前两个尖峰发生在触发扫描图像解析之后,最后一个下降发生在异常被捕获时。

问:比较虚拟字节,二等兵和#拜特斯的曲线在所有的堆,他们是彼此跟随或分歧?#Bytes在所有发散的堆中的意义是什么?(作为它在我身上的平底)
检查了内存和!address -summary MEM_IMAGE对应的PrivateBytes(113 on )。
问:内存的大部分流向哪里(哪个RegionType)?RegionUsageFree 87.15% RegionUsageIsVAF 5.64% (繁忙43.89%)通过映射到可执行映像的文件的VirtualAlloc RegionUsageImage 5.54% (繁忙43.13%)内存分配。
In WinDbg并加载了SOS,我做了一个!DumpHeap
//...
7063424c 1201 28824 System.Collections.ArrayList
706228d4 903 28896 System.EventHandler
7062f640 1253 30072 System.RuntimeType
6ec2be78 833 31216 System.Windows.Forms.PropertyStore+IntegerEntry[]
6ec2b0a4 654 34008 System.Windows.Forms.CreateParams
7063547c 318 35472 System.Collections.Hashtable+bucket[]
6ec2aa5c 664 37184 System.Windows.Forms.Control+ControlNativeWindow
70632938 716 40400 System.Int32[]
6c546700 48 49728 System.Data.RBTree`1+Node[[System.Data.DataRow, System.Data]][]
70634944 85 69600 System.Byte[]
6ec2b020 931 85972 System.Windows.Forms.PropertyStore+ObjectEntry[]
6c547758 156 161616 System.Data.RBTree`1+Node[[System.Int32, mscorlib]][]
705e6c28 2107 238912 System.Object[]
00305ce8 18 293480 Free
7062f9ac 5842 301620 System.String
Total 35669 objects下面是占用内存的顶级对象。我希望有什么东西会像拇指疼一样突出,比如大量的位图之类的东西。这里有什么东西喊出“我表现得不寻常!”对任何人吗?(我正试着逐个检查最高层的可疑事物,但最好能缩小一些可能的罪魁祸首。)
本页(地址摘要解释)是一个很大的帮助。然而,C#是我的第一语言,所以我以前没有调试内存问题的经验。想知道我是否在正确的轨道上( GC到底是个问题吗?)因为我还没有找到任何能给我任何明确指示的线索。
答:问题是由第三方图书馆引起的。我无能为力。经过深思熟虑和一些测试,用剥离的代码只涉及产生错误的方法。
我觉得我从中学到的东西都得到了赏金。
发布于 2012-03-24 16:01:28
好的,增加的信息有帮助。问题不在于您的程序使用太多内存,而是它使用的内存太少。垃圾收集堆中的数据很少。对于处理位图的程序来说,这并不少见。Bitmap类是GDI+函数的一个非常小的包装器,它只使用GC堆中的少数字节。因此,在填充gen #0堆并触发垃圾收集之前,您可以创建大量位图。这在Perfmon中也是可见的,您需要查看.NET CLR内存,GEN0集合计数器。一个健康的程序在工作时每秒大约10次触发一个集合。
不获取集合是很好的,但是当没有集合时,还有一些东西不起作用。终结器线程永远不会运行。终结器对于释放内存以外的非托管资源非常重要。就像操作系统句柄和托管对象持有的任何非托管内存指针一样。位图上有那些。
首先要做的是运行Taskmgr.exe,进程选项卡。单击“查看+选择列和勾选句柄”、“用户对象”和“GDI对象”。在程序运行时观察这些计数器。如果您看到一个没有绑定的向上攀爬,那么您就会遇到一个问题,可能导致GDI+生成OOM异常。GDI对象是常见的原因。
仔细检查代码,并检查是否在不再使用的任何图像或位图上调用that ()。小心细微的问题,比如分配PictureBox的Image。如果旧的不是空的,你就得把它处理掉。当然,这是痛苦的,而且很容易错过一个。因此,使用一个简单的策略,计算您创建的位图的数量,例如,在第100个调用GC.Collect + GC.WaitForPendingFinalizers()中触发集合和终结器扫描。
发布于 2012-03-21 01:19:23
在过去,我总是使用蚂蚁记忆分析器来处理这类事情。它不是免费的,但是对于托管代码中的内存/引用泄漏,它非常好地工作。您只需在应用程序处于稳定状态时拍摄几个快照,并查看更改。
发布于 2012-03-26 13:05:56
您可以安全地在using变量周围添加一个img块,只要稍加重构,您就可以对声明的其他图像变量进行同样的操作。
这至少应该使代码更具可读性,并减少忘记在最后块中添加一个代码的机会;我甚至可能会为解决这个问题做出贡献。不过,您似乎是在手动处理每个创建的图像对象。
https://stackoverflow.com/questions/9788230
复制相似问题