如何正确使用'using'命令?

3

我刚刚创建了这个帐户,如果我忘记了一些关键信息,请多多包涵。

我有以下代码,但我怀疑存在内存泄漏。该代码的目标是从(模拟的)相机获取图像的字节,并使用这些字节生成EmguCV图像。问题在于生成的数组长度从未保持不变。当我生成一个300x300的图像时,我期望数组包含90000个条目。但很少情况下会出现这种情况。数字不断变化。

我尝试过遵循一些有关如何正确使用“using”命令以处理变量的教程,但迄今为止我失败了。据我所知,似乎没有IDisposable功能可用于我正在使用的字节列表。因此,这可能是我失败的原因 :/

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Emgu.CV;
using Emgu.CV.Structure;

namespace opencv_test
{
    class Program
    {
        static void Main(string[] args)
        {
            Stemmer.Cvb.Image image = new Stemmer.Cvb.Image(300, 300);
            image.Initialize(125);
            List<byte> values = new List<byte>();
            CopyPixelWithValue(image, values);

            byte[] myArray = values.ToArray();

            Emgu.CV.Image<Gray, Byte> test = new Image<Gray, Byte>(300, 300);
            test.Bytes = myArray;
            test.Save("D:/abc.jpg");
        }

        static unsafe void CopyPixelWithValue(Stemmer.Cvb.Image toGetValuesFrom, List<byte> values)
        {
            int width = toGetValuesFrom.Width;
            int height = toGetValuesFrom.Height;
            var toCopyData = toGetValuesFrom.Planes[0].GetLinearAccess();

            byte* toCopyBase = (byte*)toCopyData.BasePtr;
            long toCopyYInc = toCopyData.YInc.ToInt64();
            long toCopyXInc = toCopyData.XInc.ToInt64();

            Parallel.For(0, height, y =>
            {
                var pSrcLine = toCopyBase + y * toCopyYInc;

                for (int x = 0; x < width; x++)
                {
                    var srcVal = *(pSrcLine + x * toCopyXInc);
                    values.Add(srcVal);
                }
            });
        }
    }
}

任何关于如何解决这个问题的帮助都将不胜感激!

既然数组和List<>都没有实现IDisposable接口,所以它们不支持using语句。如果它们不再需要,垃圾回收器最终会处理它们,这通常不是问题。但是,你应该检查Stemmer.Cvb.Image或Emgu.CV.Image是否实现了IDisposable接口。我认为后者实现了。在这种情况下,应该使用using (Emgu.CV.Image<Gray, Byte> test = new Image<Gray, Byte>(300, 300)) { test.Bytes = myArray; test.Save("D:/abc.jpg"); }。这将立即处理你的test对象,而不需要等待垃圾回收器运行。 - ckuri
2个回答

3
你的问题在于你正在使用一个并行循环来添加值到"values"列表中,你同时在多个线程中访问同一个列表,这是不安全的并且会破坏数据。将其改为普通循环,你可能就没有问题了。

他可以使用ConcurrentQueue,这是一种允许多线程写入的列表数据结构。 - ckuri
非常感谢!那确实是问题所在,使用普通循环可以得到预期的结果。我刚刚检查了处理时间,差异非常小,所以我会保持这种方式。 - frage12358

0

由于Parallel.For内部的非同步多线程代码,您正在丢失字节。以下是修复它的尝试。

static void Main(string[] args)
{
    Stemmer.Cvb.Image image = new Stemmer.Cvb.Image(300, 300);
    image.Initialize(125);
    byte[] myArray = GetStemmerImageBytes(image);

    Emgu.CV.Image<Gray, Byte> test = new Image<Gray, Byte>(300, 300);
    test.Bytes = myArray;
    test.Save("D:/abc.jpg");
}

static unsafe byte[] GetStemmerImageBytes(Stemmer.Cvb.Image image)
{
    int width = image.Width;
    int height = image.Height;
    var linearAccess = image.Planes[0].GetLinearAccess();

    byte* sourceBase = (byte*)linearAccess.BasePtr;
    long sourceYInc = linearAccess.YInc.ToInt64();
    long sourceXInc = linearAccess.XInc.ToInt64();

    var result = new byte[width * height];
    Parallel.For(0, height, y =>
    {
        var sourceLine = sourceBase + y * sourceYInc;

        for (int x = 0; x < width; x++)
        {
            var srcVal = *(sourceLine + x * sourceXInc);
            result[y * width + x] = srcVal;
        }
    });
    return result;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接