当前位置:编程学习 > C#/ASP.NET >>

Asp.net大内存使用,内存回收导致无响应的问题

为了提高服务器响应速度,服务器配置了8G内存,并把所有数据加载到静态变量,大约1G多的数据,
再加上运行期间的缓存等,服务器物理内存占用最高可以达到6个多G,
在运行时都会出现站点瞬间无响应的情况,

后来压力测试了一下,发现每隔1分钟,就会内存回收一次,回收的时候,tps也跌到接近0,

通过内存优化,现在内存占用最高跌到5G多,情况有所改善,但是依旧存在内存回收瞬间,站点就停止响应的问题

请教这种问题如何避免呢? --------------------编程问答-------------------- 初步怀疑是我程序里大对象太多,导致频繁进行2代对象回收造成的 --------------------编程问答-------------------- 不知道是什么意思,但是感觉很厉害 --------------------编程问答-------------------- 如果new一个对象的时候,这个对象的大小超过了85k,那么CLR就会把这个对象放在LOH上面。如果此时LOH的空间不足了,那么CLR就会启动垃圾回收器去扫描LOH堆和那个一般堆上面的第2代对象,我们之前说过,如果扫描第2代对象,就同时扫描第1代,第0代,那么实际相当于扫描了整个托管堆,性能影响可想而知。

参考:http://www.cnblogs.com/yanyangtian/archive/2011/02/17/1956768.html
--------------------编程问答-------------------- 就是很奇怪你的代码是怎么写的,而且这得多少数据才能搞到6G,挺难的吧? --------------------编程问答-------------------- 这1个多G的数据,各种组合,各种遍历做的缓存,

不过现在问题不在内存,在于如何避免回收影响站点 --------------------编程问答-------------------- 没有这么写的吧?1G的缓存放在内存中,这样子行吗?

数据库也只提供不超过100M的缓存(oracle已经算很N的数据库了,好像只有几M),是不是换个思路啊? --------------------编程问答-------------------- 这么写肯定会影响内存滴 --------------------编程问答-------------------- 没有这么用过,感觉很NB一样。 --------------------编程问答-------------------- 我有这么大的内存,为什么不能用呢?
走本地内存,总比还要经过TCPIP访问网络数据库快吧

引用 6 楼 yeness 的回复:
没有这么写的吧?1G的缓存放在内存中,这样子行吗?

数据库也只提供不超过100M的缓存(oracle已经算很N的数据库了,好像只有几M),是不是换个思路啊?
--------------------编程问答-------------------- 我考虑把站点调整为2部分,站点+程序
所有业务移到服务程序里,
站点仅负责对外响应,通过进程间通信,把用户请求反馈给程序,把程序的返回返回给用户

但是进程间通信的序列化和反序列化损耗比较大,
而且也不好控制服务停顿的超时处理

--------------------编程问答-------------------- 什么数据非得用内存来缓存?

我的建议是系统缓存+文件缓存,静态变量不是用来缓存数据的。 --------------------编程问答-------------------- 你这是站点呐,不是缓存服务器呐,这个和你机器油多大内存有半毛钱的关系啊。
你难道非要用手术刀去杀猪么?

加2级缓存吧。 --------------------编程问答-------------------- 感谢回复,
你的意思是说,站点设计时,就不应该考虑使用太多内存,是吗?


引用 12 楼 ViewStates 的回复:
你这是站点呐,不是缓存服务器呐,这个和你机器油多大内存有半毛钱的关系啊。
你难道非要用手术刀去杀猪么?

加2级缓存吧。
--------------------编程问答--------------------
引用 9 楼 youbl 的回复:
我有这么大的内存,为什么不能用呢?
走本地内存,总比还要经过TCPIP访问网络数据库快吧


数据量大,在内存里面查找到需要的数据花费的cpu很多的。

通过网络访问数据库不会慢的。

要知道,一个分布式XX管理系统的进行性能测试肯定比不过比较优秀的学生编写微型XX管理系统。

因为分布式系统得经过复杂的算法,进行定位缓存在哪个服务器,经过了网络延迟,最后进入到服务器了还得调出缓存,返回数据,又经过网络延迟被应用程序得到。
。。。

学生作业级别的微型系统,紧紧在本地操作而已,但是它负载能力肯定不如分布式这样复杂的系统。 --------------------编程问答-------------------- 这个木啥办法,毕竟iis这货回定期回收应用程序池,一旦回收了在重启必然又得重新加载你那些静态数据就像你说滴6G的数据加载完,那是受不了

我想可以考虑二级缓存,可以考虑把缓存过程放到其他非iis服务中,可以考虑分拆开搞分布式缓存 --------------------编程问答-------------------- 楼上和我想法差不多,你可以把你的程序“拆”成好几个程序域或者进程,它们之间用进程外的方式通讯。 --------------------编程问答-------------------- 感谢楼上各位的答复,我把分拆好的程序和站点,拿去试试 --------------------编程问答-------------------- 忘记回来回复了,
站点分拆为WCF进程和站点后,
问题依旧存在,WCF进程依旧会进行GC二代扫描,造成进程挂起,从而站点的请求也被挂起,

只不过分拆前是挂起IIS进程,
分拆后,是IIS的请求被WCF进程挂起

微软的GC有个通知机制,感觉不靠谱,
GC.RegisterForFullGCNotification(int maxGenerationThreshold, int largeObjectHeapThreshold)

这两个参数的含义是指的是第2代中存活的对象个数和大对象堆中对象个数,满足这两个参数后,便会引发通知

所以如果值设置太小,可能回收完毕,才收到通知;
如果设置太大,可能收到通知后,很久才回收 --------------------编程问答-------------------- 既然发现回收造成你的问题,那就不让他回收
--------------------编程问答--------------------
引用 19 楼 hdt 的回复:
既然发现回收造成你的问题,那就不让他回收


求教,如何不回收?难道用C++写代码?
我这边都是大量的Dictionary对象 --------------------编程问答-------------------- 为啥不用Cache --------------------编程问答--------------------
引用 20 楼 youbl 的回复:
Quote: 引用 19 楼 hdt 的回复:

既然发现回收造成你的问题,那就不让他回收


求教,如何不回收?难道用C++写代码?
我这边都是大量的Dictionary对象

不用C++,也可以让他不回收。 --------------------编程问答--------------------
引用 21 楼 lixiaolian7 的回复:
为啥不用Cache

在有些人看来,所谓“缓存”就是不管命中率多少,连垃圾数据也放内存里。 --------------------编程问答-------------------- 我在想,能不能加块固态硬盘进去,然后你要缓存的东西都写到这个上面去 --------------------编程问答-------------------- 说两点优化建议:
1.所有的对象能用struct的就绝不要用class
2.无论是Dictionary还是List,最好设置好Capacity


--------------------编程问答-------------------- 数据库中是加密的string数据
现有C#写的解密的方法。

如何做字段的内容搜索。

各位有高招?
--------------------编程问答--------------------  好像这个问题  我也刚遇到
 硬件配置比你高  6台1T 内存服务器 
 但数据量比你的高  加载数据一次吃掉20G 内存
 
 按照你的想法 都考虑进去 其实就是硬件提升  
 
 运行一套算法 如果生成20M 数据 当中会吃掉200M 左右内存 
 这是一个人的 缓存不会直接清掉  内存也不会马上释放 用的JAVA一套框架  如果是100个人 那就多少G了
 如果代码修改不了  只能提升硬件 --------------------编程问答-------------------- 还是搞清楚缓存该存什么东西吧!不要把缓存跟数据库混为一谈。如果你把内存当数据库用,就别提什么“回收”,你必须像保证你的数据库不被清除地一样保证内存中的所谓数据不会重启。

所谓缓存,比如说有100G内容,有3000W条(不同种类的)记录,你也可能仅在内存中放10M、几千条记录而已。这才是缓存。 --------------------编程问答--------------------
引用 9 楼 youbl 的回复:
我有这么大的内存,为什么不能用呢?

就算你有200G内存,你的缓存数据也是必要的时候才增加一条啊!怎么能一下子增加100W条?你明明仅访问 第一条数据,甚至第一条数据都没有访问时,就花时间去加载不知道什么时间才会全都访问到的另外100W条数据(而且你还无法保证在后台数据更新、也就是这些所谓缓存变成脏数据时立刻清除缓存),你的命中率是再怎么吹牛也是0%。这叫做缓存么? --------------------编程问答-------------------- 看样子你这样设计,性能不升反降。
你8g内存在服务器里面算是入门级的了,按你说你的站点一次加载1G,峰值有5~6G,

为什么被称为垃圾,因为用不到所以称为垃圾,不同等级的垃圾回收策略不一样,如果你1G的东西时时刻刻在用,我不觉得你内存配置才8G机器的CPU够用。

垃圾回收的条件
前面2种情况是严重影响系统运行的,垃圾回收会采用比较高的回收策略,而我觉得你放的东西应该都会满足这个策略,

所以怎么看你放进去的东西在你只有8G内存的服务器下始终会被快速回收。

而影响垃圾回收的性能其中几个是:
垃圾回收和性能
看来你怎么写性能影响严重

“若要回收对象,垃圾回收器必须停止应用程序的所有正在执行的线程。 在某些情况下,例如当应用程序检索数据或者显示内容时,完整垃圾回收可能会在关键时刻进行,而且可能会影响性能。”
你垃圾回收性能也不好,所以你卡了

如何避免? 你要么别怎么写,要么再加一台服务器做缓存服务器绕开。net的机制
--------------------编程问答-------------------- 我们写东西都是让资源用了尽可能的快速释放,你恰恰是反过来做,
除非那东西使用频率极高,而且生成极为消耗性能,不然一直听在内存干嘛。 --------------------编程问答-------------------- 这么大的缓存,直接靠IIS支撑,它挺难受的!
我觉得,可以考虑用缓存组件。比如memcache之类的。
但也不能把所有数据库数据都放缓存吧,比如可以每次只把登陆对象相关数据加载,过段时间定时清理。
--------------------编程问答-------------------- 感谢楼上各位的回复,
说具体一些吧:
我这边是一个搜索站点,
1、通过程序把几百万的资源 标题和简介进行分词,保存在一个字典里,并序列化为文件
  字典是:Dictionary<分词, Dictionary<资源id, 条件数据>>
2、搜索站点启动时加载并反序列化这个字典到一个静态变量
3、站点搜索时,遍历当前分词的字典,比对条件,返回资源id列表
4、程序定时把增量数据提交给站点,去刷新那个字典,以保证数据及时性

现在的问题,就是站点频繁进行2代回收,实际回收的内存并不多,主要是因为扫描的数据量太大,主要的几个问题:
1、能不能避免回收时扫描静态变量指向的所有引用?
2、如果把字典放到Redis之类的内存服务器,就增加了网络交互量 和 网络的延时,所以才考虑放在内存里,另一个考虑就是这是个对内服务的接口,如果接口慢,就会导致其它产品慢,引起连锁反应 --------------------编程问答--------------------
上面也有兄弟说做一个缓存服务器,我这边统计的结果,每天都有将近一半的量是新搜索词,而且只搜索一次,所以缓存服务器只能服务一半的量,另一半只能实时搜索。

再有就是分布式服务,我前面也说了,微软的回收通知机制太垃圾,根本不好预测哪一台即将开始回收 --------------------编程问答-------------------- 能用xml就用xml吧
Dictionary只标识xml的路径 --------------------编程问答-------------------- 不要以为机器配置高,就不注重程序的性能了

--------------------编程问答-------------------- 性能很重要。。这么玩伤不起
补充:.NET技术 ,  ASP.NET
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,