C# 来自消耗内存的锁位的位图数据

C# 来自消耗内存的锁位的位图数据,c#,.net,bitmap,gdi+,C#,.net,Bitmap,Gdi+,我有一个C#例程来获取YUV422位图并转换为RGB: private unsafe void YUV422toRGB(byte[] YUV422, int YUVstride, ref Bitmap RGB) { //Found http://pastebin.com/MFsDnUCq after I wrote this. int row, col, index; byte y1, y2, u, v; int

我有一个C#例程来获取YUV422位图并转换为RGB:

    private unsafe void YUV422toRGB(byte[] YUV422, int YUVstride, ref Bitmap RGB)
    {
        //Found http://pastebin.com/MFsDnUCq after I wrote this.

        int row, col, index;
        byte y1, y2, u, v;
        int r1, r2, g1, g2, b1, b2;
        int c1, c2, d, e;
        byte* RGBbytes;
        int RGBindex;

        //http://bobpowell.net/lockingbits.aspx
        //It looks as though this bmp guy is consuming memory to the point
        //where I must force the garbage collector or the program will crash.
        //Why?
        System.Drawing.Imaging.BitmapData bmp =
            RGB.LockBits(
            new Rectangle(0, 0, RGB.Width, RGB.Height),
            System.Drawing.Imaging.ImageLockMode.WriteOnly,
            RGB.PixelFormat);
        RGBbytes = (byte*)bmp.Scan0;
        RGBindex = 0;
        index = 0;
        for (row = 0; row < RGB.Height; row++)
        {
            for (col = 0; col < YUVstride; col += 4)
            {
                u = YUV422[index + 0];
                y1 = YUV422[index + 1];
                v = YUV422[index + 2];
                y2 = YUV422[index + 3];
                index += 4;

                c1 = y1 - 16;
                c2 = y2 - 16;
                d = u - 128;
                e = v - 128;

                int c298 = 298 * c1;
                r1 = (c298 + 409 * e + 128) >> 8;
                g1 = (c298 - 100 * d - 208 * e + 128) >> 8;
                b1 = (c298 + 516 * d + 128) >> 8;

                c298 = 298 * c2;
                r2 = (c298 + 409 * e + 128) >> 8;
                g2 = (c298 - 100 * d - 208 * e + 128) >> 8;
                b2 = (c298 + 516 * d + 128) >> 8;

                //Now for clamping.
                //From http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
                //min(x, y) = y ^ ((x ^ y) & -(x < y))
                //max(x, y) = x ^ ((x ^ y) & -(x < y))
                //We want min(x, 255) followed by max(x, 0).
                //The problem is that x < y in C# is a bool which cannot be converted to int.
                //But effectively, -(x < y) is -1 if x < y and 0 otherwise.
                //we can do this by looking at the first bit of x-y
                //min(x, y) = y ^ ((x ^ y) & ((x - y) >> 31))
                //max(x, y) = x ^ ((x ^ y) & ((x - y) >> 31))
                //There appears to be 10% or so speed increase with the bithack.

                //r1 = Math.Max(0, Math.Min(r1, 255));
                //r2 = Math.Max(0, Math.Min(r2, 255));
                //g1 = Math.Max(0, Math.Min(g1, 255));
                //g2 = Math.Max(0, Math.Min(g2, 255));
                //b1 = Math.Max(0, Math.Min(b1, 255));
                //b2 = Math.Max(0, Math.Min(b2, 255));

                r1 = 255 ^ ((r1 ^ 255) & ((r1 - 255) >> 31));
                g1 = 255 ^ ((g1 ^ 255) & ((g1 - 255) >> 31));
                b1 = 255 ^ ((b1 ^ 255) & ((b1 - 255) >> 31));
                r2 = 255 ^ ((r2 ^ 255) & ((r2 - 255) >> 31));
                g2 = 255 ^ ((g2 ^ 255) & ((g2 - 255) >> 31));
                b2 = 255 ^ ((b2 ^ 255) & ((b2 - 255) >> 31));

                r1 = r1 ^ ((r1 ^ 0) & ((r1 - 0) >> 31));
                g1 = g1 ^ ((g1 ^ 0) & ((g1 - 0) >> 31));
                b1 = b1 ^ ((b1 ^ 0) & ((b1 - 0) >> 31));
                r2 = r2 ^ ((r2 ^ 0) & ((r2 - 0) >> 31));
                g2 = g2 ^ ((g2 ^ 0) & ((g2 - 0) >> 31));
                b2 = b2 ^ ((b2 ^ 0) & ((b2 - 0) >> 31));

                RGBbytes[RGBindex + 0] = (byte)b1;
                RGBbytes[RGBindex + 1] = (byte)g1;
                RGBbytes[RGBindex + 2] = (byte)r1;

                RGBbytes[RGBindex + 3] = (byte)b2;
                RGBbytes[RGBindex + 4] = (byte)g2;
                RGBbytes[RGBindex + 5] = (byte)r2;

                RGBindex += 6;
            }
        }

        RGB.UnlockBits(bmp);
    }
private不安全void YUV422toRGB(字节[]YUV422,int-YUVstride,ref-Bitmap RGB)
{
//发现http://pastebin.com/MFsDnUCq 在我写了这个之后。
int行、列、索引;
字节y1,y2,u,v;
int r1、r2、g1、g2、b1、b2;
int c1、c2、d、e;
字节*RGBbytes;
int-RGBindex;
//http://bobpowell.net/lockingbits.aspx
//看起来这个bmp家伙正在消耗内存
//我必须强制垃圾收集器,否则程序将崩溃。
//为什么??
System.Drawing.Imaging.BitmapData bmp=
RGB.LockBits(
新矩形(0,0,RGB.宽度,RGB.高度),
System.Drawing.Imaging.ImageLockMode.WriteOnly,
像素格式);
RGBbytes=(字节*)bmp.Scan0;
RGBindex=0;
指数=0;
对于(行=0;行>8;
g1=(c298-100*d-208*e+128)>>8;
b1=(c298+516*d+128)>>8;
c298=298*c2;
r2=(c298+409*e+128)>>8;
g2=(c298-100*d-208*e+128)>>8;
b2=(c298+516*d+128)>>8;
//现在开始夹紧。
//从http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
//最小(x,y)=y^((x^y)和-(x>31))
//最大(x,y)=x^((x^y)和((x-y)>>31))
//bithack的速度似乎提高了10%左右。
//r1=Math.Max(0,Math.Min(r1255));
//r2=数学最大值(0,数学最小值(r2,255));
//g1=Math.Max(0,Math.Min(g1,255));
//g2=数学最大值(0,数学最小值(g2,255));
//b1=数学最大值(0,数学最小值(b1,255));
//b2=数学最大值(0,数学最小值(b2,255));
r1=255^((r1^255)和((r1-255)>>31));
g1=255^((g1^255)和((g1-255)>>31));
b1=255^((b1^255)和((b1-255)>>31));
r2=255^((r2^255)和((r2-255)>>31));
g2=255^((g2^255)和((g2-255)>>31));
b2=255^((b2^255)和((b2-255)>>31));
r1=r1^((r1^0)和((r1-0)>>31));
g1=g1^((g1^0)和((g1-0)>>31));
b1=b1^((b1^0)和((b1-0)>>31));
r2=r2^((r2^0)和((r2-0)>>31));
g2=g2^((g2^0)和((g2-0)>>31));
b2=b2^((b2^0)和((b2-0)>>31));
RGBbytes[RGBindex+0]=(字节)b1;
RGBbytes[RGBindex+1]=(字节)g1;
RGBbytes[RGBindex+2]=(字节)r1;
RGBbytes[RGBindex+3]=(字节)b2;
rgb字节[RGBindex+4]=(字节)g2;
RGBbytes[RGBindex+5]=(字节)r2;
RGBindex+=6;
}
}
RGB.解锁位(bmp);
}
在经典的“嘿,为什么我的程序总是在30秒后崩溃”之后,我意识到垃圾收集器没有跟上(我每秒调用这个函数10次,并且位图始终通过引用传递)

在代码中我看到,
RGB.LockBits
是提高RAM使用率的因素。我每十次调用(每秒一次)就添加一个
GC.Collect()
,现在一切都好了

我做错什么了吗?
UnlockBits
不应该自己清理吗

在代码中,我看到RGB.LockBits增加了RAM的使用。我每十次调用(每秒一次)就添加一个GC.Collect(),现在一切都好了

你说的基本上是一个普通的垃圾收集会回收所有的东西,问题是垃圾收集器没有在你期望的时候执行


你的机器内存不足吗?您是否存在实际内存压力,迫使垃圾收集器触发并回收空间?或者您是否有几GB的可用内存,以至于暂停所有线程以回收内存只是浪费cpu资源?听起来你的机器只是耸耸肩说:“呃,我这里的内存多得多。一切照旧。”

汉斯·帕桑说得对。问题是一个被复制的位图,尽管我仍然不清楚为什么这会导致垃圾收集器显然无法完成它的工作

我在这个程序中有一些后端类,它们从相机中获取图像,并将位图转换为适当的格式(例如,我发布的YUV422到RGB的转换)。传递的位图将被重用

然后我有一些UI类,其中一个是一个窗口,它在一个运行频率大约为10 Hz的计时器上显示一个新的帧。在这里,你必须复制位图,因为后端的东西将用一个新的帧替换它,等等

更新显示的例行程序很简单:

    public void SetImage(Bitmap Image)
    {
        if (this.IsDisposed) return;
        if (this.InvokeRequired)
            this.Invoke((MethodInvoker)delegate { SetImage(Image); });
        else
            picFrame.Image = (Bitmap)Image.Clone();
    }
一个摄像头提供640x480x8位(黑色a
    private Bitmap DisplayImage = null;
    public void SetImage(Bitmap Image)
    {
        if (this.IsDisposed) return;
        if (this.InvokeRequired)
            this.Invoke((MethodInvoker)delegate { SetImage(Image); });
        else
        {
            if (DisplayImage != null)
                DisplayImage.Dispose();
            DisplayImage = (Bitmap)Image.Clone();
            picFrame.Image = DisplayImage;
        }
    }