通过网络处理位图时偶尔出现 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。