通过网络处理位图时偶尔出现 OutOfMemoryException
Occasional OutOfMemoryException on Bitmap Processing Over The Network
我 运行 LinqPad 5 中的以下代码:
var client = new MongoClient(@"mongodb://192.168.0.108:27017");
var db = client.GetDatabase("Stfc");
var fitCollection = db.GetCollection<ModelFit>("RecentFits");
var fits = fitCollection.AsQueryable();
var captureCollection = db.GetCollection<Capture>("Captures");
var captures = captureCollection.AsQueryable();
var classificationCollection = db.GetCollection<Classification>("Classifications");
var classifications = classificationCollection.AsQueryable();
var modelsDir = new DirectoryInfo(@"\iansdesktop\Shared\Stfc\mymodels");
var imagesDir = new DirectoryInfo(@"\iansdesktop\Shared\Stfc\Images");
var classificationDir = new DirectoryInfo(@"C:\Users\Ian\Documents\Projects\Output\StfcBot\Classification");
var capturesById = captures.ToDictionary(x => x.Id);
var systems = classifications
.Where(x => x.Label == "system");
var count = systems.Count();
var i = 0;
var pen = new Pen(Color.FromArgb(255, 255, 0, 0));
foreach (var classification in systems)
{
var capture = capturesById[classification.CaptureId];
var img = imagesDir.File(capture.ImageName);
var srcFile = imagesDir.File(capture.ImageName);
var destFile = classificationDir.File(capture.ImageName);
while (!destFile.Exists)
{
try
{
using (var bmp = Bitmap.FromFile(srcFile.FullName))
using (var dest = new Bitmap(bmp))
{
using (var g = Graphics.FromImage(dest))
{
g.DrawEllipse(pen, capture.X - 20, capture.Y - 20, 40, 40);
}
dest.Save(destFile.FullName);
dest.Dispose();
bmp.Dispose();
}
destFile.Refresh();
destFile.Name.Dump();
}
catch (IOException ex)
{
ex.Dump();
Thread.Sleep(30_000);
}
}
++i;
if (i % 10 == 0)
{
i.ToProgressSummary(count).Dump();
}
}
我是否遗漏了什么,或者这可能是 LinqPad 中的错误?
原来这是因为位图是从网络路径加载的,网络偶尔会断开连接。
文档指出:
You must keep the stream open for the lifetime of the Bitmap.
Bitmap Constructors (See Remarks)
出于某种原因,OOM 异常混淆了正在发生的事情,但底层流正在关闭。
解决方案是将文件复制到本地并在该本地副本上进行操作:
var tmpFile = new DirectoryInfo(Path.GetTempPath()).File(srcFile.Name);
while (!destFile.Exists)
{
srcFile.CopyTo(tmpFile.FullName);
try
{
using (var bmp = Bitmap.FromFile(tmpFile.FullName))
using (var dest = new Bitmap(bmp))
{
.
}
destFile.Refresh();
destFile.Name.Dump();
}
catch (IOException ex)
{
...
}
finally
{
tmpFile.Delete();
}
}
当然如果网络仍然断开也会出现异常,但至少这是一个合理且可以理解的错误,而不是OOM。
我 运行 LinqPad 5 中的以下代码:
var client = new MongoClient(@"mongodb://192.168.0.108:27017");
var db = client.GetDatabase("Stfc");
var fitCollection = db.GetCollection<ModelFit>("RecentFits");
var fits = fitCollection.AsQueryable();
var captureCollection = db.GetCollection<Capture>("Captures");
var captures = captureCollection.AsQueryable();
var classificationCollection = db.GetCollection<Classification>("Classifications");
var classifications = classificationCollection.AsQueryable();
var modelsDir = new DirectoryInfo(@"\iansdesktop\Shared\Stfc\mymodels");
var imagesDir = new DirectoryInfo(@"\iansdesktop\Shared\Stfc\Images");
var classificationDir = new DirectoryInfo(@"C:\Users\Ian\Documents\Projects\Output\StfcBot\Classification");
var capturesById = captures.ToDictionary(x => x.Id);
var systems = classifications
.Where(x => x.Label == "system");
var count = systems.Count();
var i = 0;
var pen = new Pen(Color.FromArgb(255, 255, 0, 0));
foreach (var classification in systems)
{
var capture = capturesById[classification.CaptureId];
var img = imagesDir.File(capture.ImageName);
var srcFile = imagesDir.File(capture.ImageName);
var destFile = classificationDir.File(capture.ImageName);
while (!destFile.Exists)
{
try
{
using (var bmp = Bitmap.FromFile(srcFile.FullName))
using (var dest = new Bitmap(bmp))
{
using (var g = Graphics.FromImage(dest))
{
g.DrawEllipse(pen, capture.X - 20, capture.Y - 20, 40, 40);
}
dest.Save(destFile.FullName);
dest.Dispose();
bmp.Dispose();
}
destFile.Refresh();
destFile.Name.Dump();
}
catch (IOException ex)
{
ex.Dump();
Thread.Sleep(30_000);
}
}
++i;
if (i % 10 == 0)
{
i.ToProgressSummary(count).Dump();
}
}
我是否遗漏了什么,或者这可能是 LinqPad 中的错误?
原来这是因为位图是从网络路径加载的,网络偶尔会断开连接。
文档指出:
You must keep the stream open for the lifetime of the Bitmap.
Bitmap Constructors (See Remarks)
出于某种原因,OOM 异常混淆了正在发生的事情,但底层流正在关闭。
解决方案是将文件复制到本地并在该本地副本上进行操作:
var tmpFile = new DirectoryInfo(Path.GetTempPath()).File(srcFile.Name);
while (!destFile.Exists)
{
srcFile.CopyTo(tmpFile.FullName);
try
{
using (var bmp = Bitmap.FromFile(tmpFile.FullName))
using (var dest = new Bitmap(bmp))
{
.
}
destFile.Refresh();
destFile.Name.Dump();
}
catch (IOException ex)
{
...
}
finally
{
tmpFile.Delete();
}
}
当然如果网络仍然断开也会出现异常,但至少这是一个合理且可以理解的错误,而不是OOM。