.NET内存释放

hecker728 2010-01-25 06:18:37
使用.net的人都知道托管代码并不需要我们手动来释放内存,只要对象出了作用域,GC会自动帮我们完成回收。
我写了个GPS数据收发的服务端程序,用到Socket,多线程同步。
现在已发布,测试运行中,上线的车辆有20台。24小时不间断运行了10来天,数据收发一切正常,现在的问题是该进程占用的内存越来越大。程序刚启动,等所有车连接上内存占用35M左右,过段时间(不到1个小时)内存降为20M左右(启动时候的资源被释放),然后就一路攀升,到现在达到131M,还在不断增长中。

我程序中非托管对象,如Socket,Stream,数据库的一些对象,都Close了。不存在非托管代码没有释放。废弃的线程也进行中断后,回收了。研究一天了,不知道如何下手,如何进行内存监控,查找原因(请知道的提供测试方法)。

我分析的可能原因有:
1,非托管资源虽然Close了,但程序中没有一处显示调用GC回收(这好像不会引起GC不能自动回收吧)
2,程序中有4,5个while(true)这样的线程+20个设备的长连接数据收发线程,也是(while(true)这样的)
{
//这些线程里有很多new外部类的操作,数据库操作
A a=new A();
}
线程函数每new一次A就会在堆中申请内存空间,a就会引用新的堆地址。但是线程函数没有出作用域(无限循环)之前a所引用的堆就不会被释放,是这样的吗?但是之前a所执行的堆没有被引用了啊,线程函数一直运行的情况下a所指向的堆会回收吗?

向我这样的多线程,Socket构架下引起内存不断增加的原因有哪些,请高手指点!请不要说使用异步,20台车不多,所以这样比较方便。。
...全文
1865 72 打赏 收藏 转发到动态 举报
写回复
用AI写文章
72 条回复
切换为时间正序
请发表友善的回复…
发表回复
mrsupersky 2012-02-02
  • 打赏
  • 举报
回复
[Quote=引用 53 楼 sp1234 的回复:]

不论什么服务程序,连续运行进程10来天都很不错了。如果我做,我可能每天早晨3点钟都会自动重启进程,跟什么内存释放不释放地无关,而是因为做服务程序本来就该这样小心(或者说凭经验)地增加一些设计元素。
[/Quote]

做服务器如果 每天都要重启进程,那就完了...
服务器最好做到永不重启...
这也是所有服务器开发者的 最求吧,而程序员 在实现业务逻辑的情况下 往往 也是追求最优 资源利用率...

hecker728 2010-01-29
  • 打赏
  • 举报
回复
测试了几天,问题终于解决了。我只是加了段定时显示调用GC进行回收的代码,然后优化了下代码,保证不需要再使用的对象引用为NULL.从这几天的运行情况来看内存稳定在25-45M之间,cpu使用也基本上是0.

从这几天对CLR内存管理的深入了解来看,只要我们的.net程序不存在内存泄漏,以及明显的对程序处理不当的问题,我们就不必担心我们的程序会慢慢吃掉内存。微软似乎是这么想的“出来混,总是要还的!”
gao19870901 2010-01-27
  • 打赏
  • 举报
回复
guanzhu
guyehanxinlei 2010-01-27
  • 打赏
  • 举报
回复
实现IDispose接口 用dispose()
yuanhuiqiao 2010-01-27
  • 打赏
  • 举报
回复
while循环加个Thread.Sleep(0);试试
fut20090715 2010-01-27
  • 打赏
  • 举报
回复
先使用内存分析工具 看一下被那里吃了
期待CLR升级解决程序员内存管理永远的痛
懒... 呵呵
liushengmz 2010-01-27
  • 打赏
  • 举报
回复
再次回来,想问一下,“进程重启”会不会影响正在连接的客户端呢?

比如说一个视频系统,一天二十四小时肯定都有人连的,如果使用

进程重启的话,那么,你怎么都会影响正在连接的客户端吧?

我记得要重启进程的话,我们的做法是这样的:

假如三点要重启进程,那我们就从一点开始拒绝连客户端,把客户端

的请求转移到另外一台服务器上,到三点的时候基本就没人了,如果

还有连接都强制退掉再重启。。。重启完成后再接收新的客户端,

这样做效率低,实在不是一个好办法。。。
蘋果虫 2010-01-26
  • 打赏
  • 举报
回复
建议楼主 使用 线程 池 ,线程池 可以解决你的问题.............
longhair9711 2010-01-26
  • 打赏
  • 举报
回复
leehong0704 2010-01-26
  • 打赏
  • 举报
回复
我做的服务还要,内存消耗基本稳定。没有楼主的情况,建议的主线线程尽量简单,业务逻辑放子线程。
子线程执行完毕都,应该不再占用内存。
「已注销」 2010-01-26
  • 打赏
  • 举报
回复
学习了

帮顶

JF
messi_yang 2010-01-26
  • 打赏
  • 举报
回复
不會··幫頂了·····
ckl881003 2010-01-26
  • 打赏
  • 举报
回复
不能光靠GC,在确定可以释放掉的时候还是手工释放好
辉太郎 2010-01-26
  • 打赏
  • 举报
回复
这个问题,前些日子我一个朋友也遇到了这样的问题,他的问题是:因为要处理并发,而把两个处理放到一个线程中来处理;结果,不应该第一个处理执行的时候,被卡住了,一直过不去,因为条件不满足,所以一直在判断,循环!应该执行的第二个处理却一直没有执行!结果是线程滚线程,一直在生成新的线程,但是该执行的处理没有执行,该终止的没有终止,系统很快就挂掉了!
所以看看你的处理上是不是有不恰当得地方,而导致线程不能正常退出。
maomao90 2010-01-26
  • 打赏
  • 举报
回复
学习
悔说话的哑巴 2010-01-26
  • 打赏
  • 举报
回复
在使用的时候直接释放点看行?
aboluoyuren 2010-01-26
  • 打赏
  • 举报
回复
个人判断的解决方案如下:
1、在线程请求功能执行完成后,光GC.Collect();手动进行内存回收的是不够的,应该吧当前线程指向空:如thread = null;
2、推荐组织代码的结构例如:
using(system.data.sqlconnectin con = new system.data.sqlconnectin ("..."))
{
}
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 hecker728 的回复:]
谢谢你们提供的测试工具,我先测试,找下原因。

1,线程函数每new一次A就会在堆中申请内存空间,a就会引用新的堆地址。但是线程函数没有出作用域(无限循环)之前a所引用的堆就不会被释放,是这样的吗?但是之前a所执行的堆没有被引用了啊,线程函数一直运行的情况下a所指向的堆会回收吗?

该线程正常运行情况下,a之前所引用的对象会被自动回收吗?

2,自己new线程,当线程废弃后我也调用Threa.Abort()终止了,在ThreadAbortException中break出循环,Close掉了非托管代码。线程运行结束。

这样处理废弃线程合理吗?

这两个问题,我理解的不够。知道的给讲解下!!


[/Quote]
在没有出作用域之前,对象肯定是不会被GC释放的。当然如果你确定a没有引用任何对象了,请确保a对象有没有析构函数或者终结器,因为如果含有的话,GC需要通过至少2次以上的回收,才会释放资源。如果没有的话,建议手动销毁对象(DISPOSE)或者调用GC.Collect(0)

对于非托管资源,最好使用using(),这样能保证在使用后,能够彻底释放资源.

照楼主说的,感觉应该是在线程中NEW的对象未释放干净造成的。
hecker728 2010-01-26
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 jimh 的回复:]
基本上,如果内存足够,没有到顶,而且频繁使用内存,自动回收=不回收(回收速度赶不上使用增加速度)
所以唯有GC.Collect才有可能提前回收。
[/Quote]

有这个可能,因为线程中频繁new对象。
yyz985 2010-01-26
  • 打赏
  • 举报
回复
系统每隔十分钟清理一次,但是已分配的内存不会被释放,预留给程序备用,如果你确实做好了回收,不必在意。

private void button1_Click(object sender, EventArgs e) {
int[] arr = new int[102400 * 1024];//点几下始终都是占用400M,因为退出函数后被释放内存空间,但是占用内存还是400M,预留给下次用
}

private void button2_Click(object sender, EventArgs e) {
GC.Collect();//400M内存被收起
}
加载更多回复(50)

110,499

社区成员

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

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

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