我编写了一些代码来检索相机中的帧,以及从这些帧中获取的信息,并将它们显示在表单上。 我获得的所有数据都是非托管的,因为它来自我自己的库,用c ++编写并使用OpenCv。 我更喜欢使用单个函数调用同时获取所有数据,而不是使用OpenCv的包装器,它会多次PInvoke以获得相同的结果。此外,对我来说代码更容易维护,我对正在进行的所有事情有更多的控制权,而且我有很多其他理由喜欢这种方法。 一切都很好,(看似)完美的工作,我很高兴,但是......在我的帮助下,我希望能更好地理解。
在某一点上,我用方法
创建一个带有非托管像素数据的位图public Bitmap(int width,int height,int stride,PixelFormat format, IntPtr scan0);
我的问题如下(我有一些想法,但请告诉我,如果我是对的):
1)我没有释放scan0指向的数据,因为我认为,一旦数据归位图对象所有,它将通过垃圾收集为我完成工作。我是对的吗?
2)我不喜欢这样一个事实:每次创建和分配一个新的位图实例(除了像素数据),但我认为没有更好的方法可以从非托管数据中获取Bitmap。
3)我认为没有必要告诉垃圾收集器有大量的数据要清理GC.AddMemoryPressure(...),因为它知道它,根据初始化提供的信息进行估算。 / p>
修改
我在文档上找到了
调用者负责分配和释放scan0参数指定的内存块。但是,在释放相关的Bitmap之前,不应释放内存。
执行此操作的唯一方法是以这种方式创建的Bitmap对象保持数据不变,并且不会更改其在内存中的位置。
答案 0 :(得分:1)
1)我不会释放scan0指向的数据,因为我认为,一旦 数据由位图对象拥有,它将通过它为我完成工作 垃圾收集。我是对的吗?
不,垃圾收集器对您在非托管端初始化的对象一无所知,这就是它不受管理的原因。因此,您必须在非托管代码中调用delete来释放已分配的内存。
2)我不喜欢创建一个新的位图实例 每次分配(除了像素数据),但我想是这样 没有更好的方法可以从非托管数据中获取Bitmap。
有一种方法,关键字是unsafe。您可以在不安全的块内运行c ++代码,但必须在c#项目设置中允许这样做。因此,您可以重复使用一次初始化位图的每个像素
unsafe
{
byte stlThres = 115;
Bitmap myBmp = ...; // init the bitmap
var data = myBmp.LockBits(new Rectangle(0, 0, myBmp.Width, myBmp.Height), ImageLockMode.WriteOnly, myBmp.PixelFormat);
for (int y = 0; y < data.Height; y++)
{
byte* row = (byte*)data.Scan0 + (y * data.Stride);
//...
}
3)我认为没有必要告诉垃圾收集器 使用GC.AddMemoryPressure(...)清理大量数据 因为它知道它,从提供的信息估计 初始化。
如果您创建了一个托管的Bitmap对象(使用new),它将在超出范围后自动释放,或者不再被引用。