c#编写的winform程序长时间运行自动退出

leibo1089 2019-12-18 04:48:10
我的程序是读取NI采集卡的14个AI通道,采样率2000,采样数2000,就是1秒钟触发一次回调函数,回调函数里对每个通道2000个数据按100个一组处理后,获取20个有效数据,存入C#中的14行20列的数组。然后再把这14路AI数据添加到个chart控件里显示曲线。同时有6个串口传感器,每秒钟获取一组数据,添加到另外6个chart控件里显示曲线,串口数据接收是用6个C#的串口控件实现的。
现在程序运行1个小时左右没问题,但是再长时间可能会退出,在Windows的日志里看到的如下面图片中的错误。请问各位大神这是什么错误,大概怎么解决?
另外,我在测试时发现任务管理器里的程序的内存占用会上升,刚开始是40MB左右,1个小时候会升到50多兆,甚至70多兆,连续观察会发现大部分时间内存是缓慢增几分钟,大概增加1-2MB,然后掉下来,然后再缓慢增几分钟,再掉下来,但是整体是上升的,但是有时候会发现内存会突然增加几兆,还不掉下来。请大神们帮帮忙,漫无目的的测试好累啊。

...全文
1478 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
bluesen 2020-01-02
  • 打赏
  • 举报
回复
内存泄漏了吧。像这种频繁周期性调用的程序,不如用C/C++改写,手工管理内存,至少应该用C/C++写个dll给C#调用。
leibo1089 2020-01-01
  • 打赏
  • 举报
回复
引用 37 楼 luj_1768 的回复:
实在记不起来了,通常使用文件类型的存取长度都是64k,但是c++支持长文件、可能只要声明一下或者标记一下就行了,具体的需要查看相关的头文件。有的时候是这样做的:文件名使用字母加序号的方式命名,放在一个目录下,满长度后就新建一个文件;这样存取、查询都可能会快一些,只是需要规划好使用与检索方案。
引用 39 楼 huakai2418 的回复:
1.日志还是不要自己去记录,多线程访问会挂死、文件读写可能会异常等问题如影随行,没得5年技术会经常踩坑的,推荐你使用log4net日志库 2.CPU飙升到40~50%肯定不是static变量多导致的,而是程序中处理的数据量大导致的,你得查下,而且很好查:一种是日志打印数据量,打印处理时间来分析,另一种是使用VS的Analyze工具来调试运行,对CPU进行采样,得到CPU占用路径,进而分析业务逻辑
感谢你们的回复,下一步要测一下cpu占用率飙升的问你了,你给我提供了很好的思路,拜谢。
luj_1768 2019-12-25
  • 打赏
  • 举报
回复
实在记不起来了,通常使用文件类型的存取长度都是64k,但是c++支持长文件、可能只要声明一下或者标记一下就行了,具体的需要查看相关的头文件。有的时候是这样做的:文件名使用字母加序号的方式命名,放在一个目录下,满长度后就新建一个文件;这样存取、查询都可能会快一些,只是需要规划好使用与检索方案。
huakai2418 2019-12-25
  • 打赏
  • 举报
回复
1.日志还是不要自己去记录,多线程访问会挂死、文件读写可能会异常等问题如影随行,没得5年技术会经常踩坑的,推荐你使用log4net日志库
2.CPU飙升到40~50%肯定不是static变量多导致的,而是程序中处理的数据量大导致的,你得查下,而且很好查:一种是日志打印数据量,打印处理时间来分析,另一种是使用VS的Analyze工具来调试运行,对CPU进行采样,得到CPU占用路径,进而分析业务逻辑
leibo1089 2019-12-24
  • 打赏
  • 举报
回复
引用 26 楼 luj_1768 的回复:
哈哈,提示一下:*.txt,最初的最大容量是64k。不知后来扩展没有,当初有超过这一限制的,但是技术细节我没打听。
我的程序原来是每天生成一次日志文件,最大时候有1G以上
leibo1089 2019-12-24
  • 打赏
  • 举报
回复
引用 23 楼 大然然 的回复:
人家都把代码贴出来了居然那么多人看不到问题所在, 楼主用的是try finally, 而不是try catch finally, 也就是说代码里出错的话是捕获的不到的,直接崩掉, 至于代码里的错,Directory.CreateDirectory("D:/Error/" + filename); ,这句是会出错的,你这个是文件路径,但你却当成了文件夹路径去create, 你创建出来的是一个名字为XXXX.txt的文件夹,不是真的txt,也就是说这个文件夹是空的,然后你直接向这个文件夹(不是文件)写内容,不出错才怪。 最后总结一句, c:\123\ddd.txt 这个本来应该是txt的文件路径,你却弄成了一个叫ddd.txt的文件夹,文件夹里是空的
谢谢你的回复,确实没用catch,这一点我也没注意,我再测试一下。 另外,你指出Directory.CreateDirectory("D:/Error/" + filename); 会出错,这个语句是创建文件夹,而不是创建文件。 但是我的程序已经调试一段时间了,每小时会自动生成一次新的日志文件,还没有因为生不成文件而出错,不过这可能也是个漏洞,我认真查一下。
日拱一两卒 2019-12-23
  • 打赏
  • 举报
回复
即使你有catch,catch里面的写日志方法又该让谁来catch?
日拱一两卒 2019-12-23
  • 打赏
  • 举报
回复
垃圾回收,内存释放,多线程,都是问题
weixin_46014019 2019-12-23
  • 打赏
  • 举报
回复
技术贴。看这头晕打发士大夫的
weixin_46063668 2019-12-23
  • 打赏
  • 举报
回复
编辑软件全是肉丝汤姆猫咪后院
wxf54318 2019-12-23
  • 打赏
  • 举报
回复
是不是使用了非托管的结构或是使用了static结构导致不能有效回收资源。
luj_1768 2019-12-21
  • 打赏
  • 举报
回复
哈哈,提示一下:*.txt,最初的最大容量是64k。不知后来扩展没有,当初有超过这一限制的,但是技术细节我没打听。
leibo1089 2019-12-20
  • 打赏
  • 举报
回复
引用 18 楼 _stephen_chow 的回复:
NI的东西用labview搞方便
感谢你的回复,我没用过labview做东西,labview做NI的读取和显示应该很方便吧,能和数据库结合吗?一般是什么数据库?labview里面有没有各种通信接口?比如串口、USB、IIC、SPI等,方便和其他设备连接。
leibo1089 2019-12-20
  • 打赏
  • 举报
回复
引用 12 楼 Bridge_go 的回复:
写入文件不能同时写入,最好加个锁。
引用 13 楼 正怒月神 的回复:
书写日志的代码发出来, 是单例的吗?
引用 14 楼 胖叔叔写代码 的回复:
写日志的代码发出来吧,估计是多线程写文件冲突了。 解决方案无非是异步写文件或者日志操作单例化。
引用 15 楼 Summer_djz 的回复:
多线程写文件会有问题,你可以用log4net写日志,很简单
引用 16 楼 tangyanzhi1111 的回复:
多线程首先要想到的释放规范,否则崩溃也是很正常的事情
引用 17 楼 雪狼孤竹 的回复:
先加try……catch 来定位。 然后看是什么引起的,是可避免的,还是没法避免的。 可避免的,针对性的找方法解决; 不可避免的,加try……catch,catch无参数,无执行。
感谢你们的回复,学到了新知识。
leibo1089 2019-12-20
  • 打赏
  • 举报
回复
昨天按照6#和8#朋友的提示,将后台写日志的代码屏蔽掉,从上午开始测试到下午下班,有31800多秒,没有再出SYSTem.IO的错误,看来确实是写日志文件的影响。 昨天下午一直忙,没来得及回帖,代码也没来得及贴,现在贴出来大家可以评判一下。 多线程写入文件的代码主要就是调用两个写好的文件写入函数,内部代码都差不多,只是在程序中用法不同,一个是写运行日志,一个是写错误日志,代码如下: public static class WriteLog { private static readonly object _locker = new object(); private static readonly object _locker2 = new object(); [Conditional("WRERR")] public static void writeerror(Exception ex, string mess = "") { string errortime = "发生时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); string errorinfo = "异常信息:" + ex.Message; string errorsourse = "错误源:" + ex.Source; string errorTrance = "堆栈信息:" + ex.StackTrace; StreamWriter writer = null; try { object locker = WriteLog._locker; lock (locker) { DateTime.Now.Year.ToString(); DateTime.Now.Month.ToString(); DateTime.Now.Day.ToString(); string Path = string.Empty; string FileName = "错误日志" + DateTime.Now.ToString("yyyyMMdd") + ".txt"; if (!Directory.Exists("D:/Error")) { Directory.CreateDirectory("D:/Error"); } Path = "D:/Error"; if (!Directory.Exists(Path)) { Directory.CreateDirectory(Path); } writer = new StreamWriter(new FileInfo(Path + "/" + FileName).FullName, true); writer.WriteLine(errortime); writer.WriteLine(errorinfo); writer.WriteLine(errorsourse); writer.WriteLine(errorTrance); writer.WriteLine(mess); writer.WriteLine("---------------------------------------------------------------------------------------------------------"); } } finally { if (writer != null) { writer.Close(); } } } [Conditional("WRLOG")] public static void writelog(string filename, string message) { StreamWriter writer = null; try { object locker = WriteLog._locker2; lock (locker) { DateTime.Now.Year.ToString(); DateTime.Now.Month.ToString(); DateTime.Now.Day.ToString(); string Path = string.Empty; string FileName = "记录" + DateTime.Now.ToString("yyyyMMdd") + ".txt"; if (!Directory.Exists("D:/Error/" + filename)) { Directory.CreateDirectory("D:/Error/" + filename); } Path = "D:/Error/" + filename; if (!Directory.Exists(Path)) { Directory.CreateDirectory(Path); } writer = new StreamWriter(new FileInfo(Path + "/" + FileName).FullName, true); writer.WriteLine(DateTime.Now.ToString() +"--"+ message); writer.WriteLine("---------------------------------------------------------------------------------------------------------"); } } finally { if (writer != null) { writer.Close(); } } } public static void log(string message, string filename) { WriteLog.writelog(filename, message); } } 我在程序中使用这两个函数的代码很多,但是用法都一样,在try里调用写运行日志的函数,在catch里调用写错误日志的函数,我贴一个使用的方法,其他用法都是类似的。 private static void stopTestDecide(int chNum, Label labelLedGas,Button btnStopMeas) { try { //保存最新的两个二极管电压到maxVoltage的第一行 //int index = 0; //Label labelLedGas = ZDCS.zdcs.labelLedCh1Gas; if (labelLedGas.ForeColor == Color.Green) { ZDCS.maxVoltage[chNum, 0] = ZDCS.data2ChartX5[0, 0];//第一路电压 ZDCS.maxVoltage[chNum, 1] = ZDCS.data2ChartX5[1, 0];//第二路电压 WriteLog.writelog("debugLog", "stopTestDecide函数:ZDCS.maxVoltage[" + chNum.ToString() + ", 0]=" + ZDCS.maxVoltage[chNum, 0].ToString() + ",ZDCS.maxVoltage[" + chNum.ToString() + ", 1]=" + ZDCS.maxVoltage[chNum, 1].ToString()); } double volOfThread = Convert.ToDouble(DbHelperSQL.GetSingle("SELECT [para4] FROM [test].[dbo].[SysPara] where name='AIPara'").ToString()); if (labelLedGas.ForeColor == Color.Red && ZDCS.maxVoltage[chNum, 0] > 1.0 && ZDCS.maxVoltage[chNum, 0] < 1.1 && ZDCS.maxVoltage[chNum, 0] - ZDCS.data2ChartX5[0, 0] > volOfThread / 1000) { //ZDCS.zdcs.btnStopMeasure.PerformClick(); btnStopMeas.PerformClick(); WriteLog.writelog("debugLog", "stopTestDecide函数:第一路达到条件"); } else if (labelLedGas.ForeColor == Color.Red && ZDCS.maxVoltage[chNum, 1] > 1.0 && ZDCS.maxVoltage[chNum, 1] < 1.1 && ZDCS.maxVoltage[chNum, 1] - ZDCS.data2ChartX5[1, 0] > volOfThread / 1000) { btnStopMeas.PerformClick(); WriteLog.writelog("debugLog", "stopTestDecide函数:第二路达到条件"); } } catch (Exception ex) { WriteLog.writeerror(ex, "stopTestDecide校正数据出错,ex.message=" + ex.Message); } } 另外还有一个细节没有说明,就是我为了在多个窗口中相互调用方便,把一些频繁调用的函数定义成了static类型的函数,这样就可以直接调用,当然为了传递参数,这些参数也必须是static静态的,我的问题是,频繁调用static函数,频繁使用static变量,长时间运行会不会导致内存上升很厉害,我的程序运行2个小时候,在任务管理器里看到程序的内存(专用工作集)占用从刚打开的40MB左右,增长到90MB左右,CPU那一列会从开始的10左右,增长到40-50,这个不知道是不是这些静态函数,静态变量的频繁使用导致的?如果不是那可能是什么原因呢?
萌虎生威 2019-12-20
  • 打赏
  • 举报
回复
引用 23 楼 大然然 的回复:
人家都把代码贴出来了居然那么多人看不到问题所在,
楼主用的是try finally, 而不是try catch finally, 也就是说代码里出错的话是捕获的不到的,直接崩掉,
至于代码里的错,Directory.CreateDirectory("D:/Error/" + filename); ,这句是会出错的,你这个是文件路径,但你却当成了文件夹路径去create, 你创建出来的是一个名字为XXXX.txt的文件夹,不是真的txt,也就是说这个文件夹是空的,然后你直接向这个文件夹(不是文件)写内容,不出错才怪。
最后总结一句, c:\123\ddd.txt 这个本来应该是txt的文件路径,你却弄成了一个叫ddd.txt的文件夹,文件夹里是空的

楼主测试过了嘛? 分享一下了 学习一下
BingdianAnnie 2019-12-20
  • 打赏
  • 举报
回复
labview
大然然 2019-12-20
  • 打赏
  • 举报
回复
人家都把代码贴出来了居然那么多人看不到问题所在,
楼主用的是try finally, 而不是try catch finally, 也就是说代码里出错的话是捕获的不到的,直接崩掉,
至于代码里的错,Directory.CreateDirectory("D:/Error/" + filename); ,这句是会出错的,你这个是文件路径,但你却当成了文件夹路径去create, 你创建出来的是一个名字为XXXX.txt的文件夹,不是真的txt,也就是说这个文件夹是空的,然后你直接向这个文件夹(不是文件)写内容,不出错才怪。
最后总结一句, c:\123\ddd.txt 这个本来应该是txt的文件路径,你却弄成了一个叫ddd.txt的文件夹,文件夹里是空的
_stephen_chow 2019-12-20
  • 打赏
  • 举报
回复
labview搞硬件通讯和信号处理很方便的,它是基于数据流编程的。适合测控,但业务比较复杂的场景还是高级语言编程吧。
leibo1089 2019-12-19
  • 打赏
  • 举报
回复
引用 8 楼 的回复:
IO操作还真有可能是多线程处理导致的 有没有考虑数据同步呢? 把多线程写入文件的代码贴出来
谢谢你的回复,我不太理解你说的“数据同步”是什么意思,是采集的数据同步还是写入日志的数据同步?
加载更多回复(17)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧