C# 多线程 内存溢出

飘飘故我在 2015-08-13 10:38:57
C#写了一个程序。
函数A
{
操作..........
}
-----------------------------------------------
函数B
{
//声明线程调用函数A
Thread Thread1 = new Thread(new ThreadStart(函数A));
Thread1.Start();
}
-------------------------------------------------
然后,每隔一段时间调用函数B(差不多500毫秒一次),运行一段时间后就报System.OutOfMemoryException异常。但是定义线程调用A,执行完之后,应该就结束了,资源应该释放啊了,为啥还把内存溢出。
PS:自己试过指定线程大小Thread Thread1 = new Thread(new ThreadStart(函数A),1024 * 256);也会报内存溢出错误,只不过比之前的耗时长一些
...全文
1045 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
吉普赛的歌 2015-08-22
  • 打赏
  • 举报
回复
你这个问题的重点在DB上而不是程序的多线程。 查询应该类似: select * from t with(nolock) 避免死锁
zhouxingyu896 2015-08-15
  • 打赏
  • 举报
回复
楼主的程序还是要给个结束的点。 死循环,不好了.要不就给个可以再次运行的条件了。
在飞的特拉斯 2015-08-15
  • 打赏
  • 举报
回复
引用 13 楼 sp1234 的回复:
假设你要每隔500毫秒处理一次数据库中的数据,那么你就应该真的在前一次处理数据完毕之后才使用定时器来定时到500毫秒之后才执行下一次数据处理。同一时间就不应该同时进行重复的(重叠的)数据处理。而且定时器本身并不额外占用什么线程。 另外访问数据进行遍历、处理的,通常都是重度占用CPU(几乎占用100%)的任务。应该在有特定的事件准确出现之后才启动处理,而不应该任意地定时轮询。你的轮询间隔时间设置的大或者小,往往都是不可行的,这个机制本身就是一个麻烦制造者。 从逻辑上说,任务设计应该是具体的和离散的,而不应该是批量的还重度查询的。例如有10万个人订票,那么每一个人的订票操作应该分别单独、并发地执行,而不是弄一个什么200毫秒的轮询去到数据库里去查询一批订票请求去批处理。一个真正的批处理往往是每小时启动一次,或者每天才启动一次。而你每500毫秒启动一次,十有八九就是在滥用。
请教一下,如果是两个应用共用一个db,一边是异步的写入,另一边是定时的读取;像这种架构如何优化呢?
jy251 2015-08-14
  • 打赏
  • 举报
回复
引用 12 楼 sp1234 的回复:
什么“循环、阻塞、队列”之类的东西,都是多线程并发程序设计的大忌,而且它们连环相套地出现。要解决它们,要从根本上重新学明白,从删除“循环、阻塞、队列”开始。
请教一下,没看明白,如果一个设计是这样的: 后台固定有X个线程等待处理请求,请求接受的速度大于请求处理的速度。 面对这样一个设计的话,如果不用阻塞和队列机制,那应该如何设计啊?
於黾 2015-08-14
  • 打赏
  • 举报
回复
引用 14 楼 jy251 的回复:
[quote=引用 12 楼 sp1234 的回复:] 什么“循环、阻塞、队列”之类的东西,都是多线程并发程序设计的大忌,而且它们连环相套地出现。要解决它们,要从根本上重新学明白,从删除“循环、阻塞、队列”开始。
请教一下,没看明白,如果一个设计是这样的: 后台固定有X个线程等待处理请求,请求接受的速度大于请求处理的速度。 面对这样一个设计的话,如果不用阻塞和队列机制,那应该如何设计啊?[/quote] 就是让你不要有固定的几个线程在那里处理,而是使用线程池来动态创建线程处理 如果你是固定的几个线程,那么即使没有任何任务,线程依然要维持生存,那么就离不开循环,阻塞
骨灰级粉丝 2015-08-14
  • 打赏
  • 举报
回复
[System.Runtime.InteropServices.DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize")] public static extern int SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize); /// <summary> /// 释放内存 /// </summary> public static void ClearMemory() { GC.Collect(); GC.WaitForPendingFinalizers(); if (Environment.OSVersion.Platform == PlatformID.Win32NT) { Form2.SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); } }
  • 打赏
  • 举报
回复
假设你要每隔500毫秒处理一次数据库中的数据,那么你就应该真的在前一次处理数据完毕之后才使用定时器来定时到500毫秒之后才执行下一次数据处理。同一时间就不应该同时进行重复的(重叠的)数据处理。而且定时器本身并不额外占用什么线程。 另外访问数据进行遍历、处理的,通常都是重度占用CPU(几乎占用100%)的任务。应该在有特定的事件准确出现之后才启动处理,而不应该任意地定时轮询。你的轮询间隔时间设置的大或者小,往往都是不可行的,这个机制本身就是一个麻烦制造者。 从逻辑上说,任务设计应该是具体的和离散的,而不应该是批量的还重度查询的。例如有10万个人订票,那么每一个人的订票操作应该分别单独、并发地执行,而不是弄一个什么200毫秒的轮询去到数据库里去查询一批订票请求去批处理。一个真正的批处理往往是每小时启动一次,或者每天才启动一次。而你每500毫秒启动一次,十有八九就是在滥用。
  • 打赏
  • 举报
回复
什么“循环、阻塞、队列”之类的东西,都是多线程并发程序设计的大忌,而且它们连环相套地出现。要解决它们,要从根本上重新学明白,从删除“循环、阻塞、队列”开始。
gw6328 2015-08-13
  • 打赏
  • 举报
回复
多线程不要乱用吧。 500ms开一个,一般的处理不会这样,线程不是越多越好。 用异步试试,如楼上所说的task来试试
  • 打赏
  • 举报
回复
引用 5 楼 youlong198808 的回复:
线程调用的函数是while(true)循环,通过Thread.Sleep(100)间隔
这种函数中不要写这类循环,也不应该写 Sleep。如果没事干,就应该结束函数。可能是你不知道如何事件驱动函数,所以去弄一个死循环;然后因为死循环太恶心了,所以就想到了线程这个玩意儿。你这是很不好的程序设计习惯,应该从“头”开始重新整理设计思路(从事件驱动的设计开始),而不是太技术化地纠结线程问题。
by_封爱 版主 2015-08-13
  • 打赏
  • 举报
回复
这种情况 都用timer或者线程池或者task 因为timer也是线程池管理的 那种 Thread1 = new Thread(); 之类的代码 只能看而已.....
_lee_chong 2015-08-13
  • 打赏
  • 举报
回复
引用 5 楼 youlong198808 的回复:
因为用的是线程,所以问一个问题;我定义一个线程,但是new了多次,线程默认大小是1M。如下啊: Thread Thread1 = null; 下面我new2次 Thread1 = new Thread(线程调用的函数); Thread1.start(); Thread1 = new Thread(线程调用的函数); Thread1.start(); 线程调用的函数是while(true)循环,通过Thread.Sleep(100)间隔 最终用的内存是2M 还是1M,就是内存分配是在定义时候分配,还是new时候分配。。。C#新手。。。还望见谅
如果你的线程没结束,那么是2m,另外如果你说的默认内存1m是指的线程函数中的内存,那么那1m自然是在thread.start开启线程后分配的; 另外可参考6,7楼,也就我上面所说的第三个方法限制线程数量,没节制的不停开线程不是什么好主意
winnowc 2015-08-13
  • 打赏
  • 举报
回复
这种需求使用大量线程处理本身就不合理,大量线程资源被用来等待数据库操作。合理的方案是计算和保存数据分离,如果计算量大,可以多线程并行计算,把结果存入一个队列中;使用几个线程(很可能一个就够,看数据库的吞吐能力)从这个队列中取结果,保存到数据库。就是标准的生产者/消费者模型,内存的占用可以通过队列容量上限来控制。
winnowc 2015-08-13
  • 打赏
  • 举报
回复
这种需求使用大量线程处理本身就不合理,大量线程资源被用来等待数据库操作。合理的方案是计算和保存数据分离,如果计算量大,可以多线程并行计算,把结果存入一个队列中;使用几个线程(很可能一个就够,看数据库的吞吐能力)从这个队列中取结果,保存到数据库。就是标准的生产者/消费者模型,内存的占用可以通过队列容量上限来控制。
飘飘故我在 2015-08-13
  • 打赏
  • 举报
回复
因为用的是线程,所以问一个问题;我定义一个线程,但是new了多次,线程默认大小是1M。如下啊: Thread Thread1 = null; 下面我new2次 Thread1 = new Thread(线程调用的函数); Thread1.start(); Thread1 = new Thread(线程调用的函数); Thread1.start(); 线程调用的函数是while(true)循环,通过Thread.Sleep(100)间隔 最终用的内存是2M 还是1M,就是内存分配是在定义时候分配,还是new时候分配。。。C#新手。。。还望见谅
_lee_chong 2015-08-13
  • 打赏
  • 举报
回复
1,优化代码逻辑,将循环内每次都要申请内存的操作提取到循环外面,每次循环都共用一块内存;(不是每种内存占用都能这么做) 2,手动gc。。。(性能低,不过可以平滑处理,比如100次循环手动回收一次) 3,限制内存使用频率,如果代码环境代码环境是多线程导致内存过多,就限制线程数量,如果是循环导致,就降低循环速度,比如加个thread.sleep等; 1效果最好,可惜不是什么时候都适用,2代码简单,可惜性能损坏高,3比较中庸肯定可用,但是会降低执行效率; 这是之前回答别人的,处理内存溢出的方式,只是他是循环你是多线程而已,性质是一样
飘飘故我在 2015-08-13
  • 打赏
  • 举报
回复
引用 1 楼 lc316546079 的回复:
函数a里代码是什么,500毫秒,这频率,如果函数a操作时间过长,内存会有内存溢出可能
函数a里面是对数据的分析,然后保存数据库。耗时有可能会超过500毫秒。 那如何解决这个问题?
飘飘故我在 2015-08-13
  • 打赏
  • 举报
回复
引用 1 楼 lc316546079 的回复:
函数a里代码是什么,500毫秒,这频率,如果函数a操作时间过长,内存会有内存溢出可能
函数a里面是对数据的分析,然后保存数据库。耗时有可能会超过500毫秒。 那如何解决这个问题?
_lee_chong 2015-08-13
  • 打赏
  • 举报
回复
函数a里代码是什么,500毫秒,这频率,如果函数a操作时间过长,内存会有内存溢出可能

111,092

社区成员

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

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

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