Dispose()
都可以用,一个视频内存占用也就100~200Mpublic void OpenVideo()//打开rtsp视频
{
Capture = new VideoCapture(rtspUrl);
int count =0
while (!StopFlag)
{
if (Capture == null || Capture.IsDisposed)
{
break;
}
Mat mat = new Mat();
bool res = Capture.Read(mat);//会阻塞线程
if (!res || mat.Empty())
{
count ++;
if(count >50)break;//可能链接无效,线程退出
mat.Dispose();
continue;
}
count =0;
if (SaveFlag && VideoWriter != null)
{
VideoWriter.Write(mat);
}
if (PictureBox != null)
{
System.Drawing.Image image = PictureBox.Image;
PictureBox.Image = BitmapConverter.ToBitmap(mat);
if (image != null)
{
image.Dispose();//释放以前的图片,不然吃内存
}
}
Cv2.WaitKey(1);
mat.Dispose();
}
Capture.Dispose();
}
public void CloseVideo(){//关闭rtsp视频
StopFlag = true;
}
public void StartOpenVideo(){
Thread th = new Thread(OpenVideo);
th.Start();
}
线程里,这句话执行普遍在20—60ms,单独执行方法,这句话执行普遍7—13ms
bool res = Capture.Read(mat);//会阻塞线程
Cv2.WaitKey(1);
把那个1修改大一些,内存就涨得慢一些……那个和Thread.Sleep()不一样吗?还是内存为啥涨啊?
这个该怎么解决?
你的StopFlag在循环中未发生改变,死循环,并且对象的初始化操作不建议放在循环内部
线程, 本来就是拿他来跑死循环的,Mat mat = new Mat();
初始化不放循环里,好像这个东西不会被回收,我当初测试发现这个了,我再测试一次去
所以我的mat 在循环里手动Dispose了
放外面也不行
stopFlag我用来做停止线程的标志了,是这个类的成员变量
@小草上飞飞: 其实他不会走到mat.DIspose()的,bool res = Capture.Read(mat);这行代码需要等待,所以res的值不会马上给你,下边你有一个逻辑判断,if (!res || mat.Empty())
{
continue;
}
mat是空的,所以会不停地创建mat对象
@Evilloafer: 我现在修改了那段代码,同时修改了博问。
我在昨天也以为时这个问题,我添加了几处Dispose,但是还是不行。
@小草上飞飞: 你不要用Dispose了,
public void OpenVideo()//打开rtsp视频
{
Capture = new VideoCapture(rtspUrl);
int count =0
Mat mat = null;
while (!StopFlag)
{
if (Capture == null || Capture.IsDisposed)
{
break;
}
if (mat == null)
{
mat = new Mat();
}
bool res = Capture.Read(mat);//会阻塞线程
if (!res || mat.Empty())
{
count ++;
if(count >50)break;//可能链接无效,线程退出
continue;
}
count =0;
if (SaveFlag && VideoWriter != null)
{
VideoWriter.Write(mat);
}
if (PictureBox != null)
{
System.Drawing.Image image = PictureBox.Image;
PictureBox.Image = BitmapConverter.ToBitmap(mat);
if (image != null)
{
image.Dispose();//释放以前的图片,不然吃内存
}
}
Cv2.WaitKey(1);
mat.Dispose();
}
Capture.Dispose();
}
@Evilloafer: 我试试
@小草上飞飞: 还有一个问题就是如果只需要读取一次的话,建议你改变stopFlag,停止死循环
@Evilloafer: 这个是播放视频的,每次只抓取一帧像,然后赋给picturebox
@Evilloafer:
这个也不行
难不成只能使用C++?
@小草上飞飞: SaveFlag、VideoWriter、PictureBox都是对象名吗
@Evilloafer: SaveFlag,bool型,是存.mp4文件的标志,VideoWriter 是将图片写入mp4文件的对象,PictureBox 就是抓取到的图要赋给这个图片框显示出来。都是这个类的成员变量
@Evilloafer: 内外网分离,只能拍照片了
@小草上飞飞: 你有调试吗,他能不能走到为PictureBox赋值,现在不行是指图片显示不出来?
@Evilloafer: 现在的问题是,内存占用特别多。
单独调用方法,放按钮事件里,事件方法最后一个调用,播放一个视频也就不到200M内存,
放线程里,内存使用随时间递增,几分钟就20多G,这谁也顶不住啊
@Evilloafer: 功能是ok的
@小草上飞飞: System.Drawing.Image image = PictureBox.Image;
PictureBox.Image = BitmapConverter.ToBitmap(mat);
if (image != null)
{
image.Dispose();//释放以前的图片,不然吃内存
}
这里的image对象没有一点用处
@Evilloafer: 为了释放掉
@小草上飞飞: 你试试
if(PictureBox.Image!=null) PictureBox.Image.Dispose();
PictureBox.Image = BitmapConverter.ToBitmap(mat);
@小草上飞飞: 如果还是不行,你试试这样写
public void OpenVideo()//打开rtsp视频
{
Capture = new VideoCapture(rtspUrl);
int count =0
Mat mat = null;
while (!StopFlag)
{
if (Capture == null || Capture.IsDisposed)
{
break;
}
if(mat == null)
{
mat = new Mat();
}
bool res = Capture.Read(mat);//会阻塞线程
if (!res || mat.Empty())
{
count ++;
if(count >50)break;//可能链接无效,线程退出
continue;
}
count =0;
if (SaveFlag && VideoWriter != null)
{
VideoWriter.Write(mat);
}
if (PictureBox != null)
{
if(PictureBox.Image != null) PictureBox.Image.Dispose();
PictureBox.Image = BitmapConverter.ToBitmap(mat);
}
Cv2.WaitKey(1);
mat=null;
}
Capture.Dispose();
}
@Evilloafer: 这样我干过了,不行,
if(PictureBox.Image != null) PictureBox.Image.Dispose();
PictureBox.Image = BitmapConverter.ToBitmap(mat);
这两行会直接让程序崩溃,非法访问内存
@小草上飞飞: 好吧
@Evilloafer: 这就是样例,我照着写的
@Evilloafer: 只不过把两个读取视频和录制视频两个类合并到一个类了,原生OpenCv也是这么写的,直接放线程中,但是C++为啥会回收,C#不会
@小草上飞飞: 你可以把PictureBox
那几行注释掉,排除下错误
@slowstart: 试了,我也单步调试的话,发现image有被Dispose,因为里面的属性全没了
@slowstart: 注释掉不影响结果,太骚了
你是怎么使用StartOpenVideo这个方法的
StartOpenVideo 这个方法放按钮Click的事件里面
这俩一方法,都是在同一个位置被调用。因为我最开始没用线程,现在发现卡住主线程了,才启用线程,然后发现内存变了
@小草上飞飞: 这个按钮只点一次的吧
@slowstart: 点第二次会关闭第一次打开的线程
在 while 循环中阻塞线程,不狂飙才快呢,线程池中的线程什么都不怕,就怕阻塞,建议使用异步方法
主线程没有使用线程池,new Thread
用了线程池
@dudu: 没懂
@dudu: 讲细一点
@dudu: 或者说怎么解决
@dudu: 你的意思是 bool res = Capture.Read(mat);//会阻塞线程
这一行阻塞了线程?
@小草上飞飞: 注释中不是写了“会阻塞线程”吗?
@dudu: 是的,没有下一张图,他就会在那里等着
@dudu: 有没有啥解决办法?这个是OpenCvSharp的例子,不是很会改它
@dudu: 我没有找到 线程中调用阻塞线程方法 会增加内存的解释或者相关的,我不是很懂这块,能讲细致点嘛?
@小草上飞飞: 下面的代码有点问题,应该先 Dispose 后 break
if(count >50)break;//可能链接无效,线程退出
mat.Dispose();
@dudu: 这只能影响到一个mat,一张图片大小,而且break之后,线程方法就执行完了,该回收了,里面变量也就回收了