我有一个网络客户端处理来自服务器的数据。
数据是作为一系列消息发送的,这些消息本身就是键/值集合,在概念上类似于headers (除了没有“消息体”),下面是一个典型的单向消息(由\r\n分隔的行):
Response: OK
Channel: 123
Status: OK
Message: Spectrum is green
Author: Gerry Anderson
Foo123: Blargh我的协议客户端通过使用NetworkStream逐字读取StreamReader和while( (nc = rdr.Read()) != -1 )来工作,并使用状态机解析器和StringBuilder实例填充Dictionary<String,String>实例。然后将这些字典实例保存到内存中的结构中,以便进一步处理,通常每个字典实例的使用寿命约为10分钟。
我的客户端每小时收到数千条这样的消息,而且客户端进程持续时间很长--这是一个问题,因为我的客户端进程经常会消耗超过2GB的内存,所有这些String实例都来自我--我使用windbg查看所有内存的去向。这是一个问题,因为代码运行在只有3.5GB内存的Azure上。我看不出为什么我的程序最多要消耗几百MB的RAM。我经常会照看VM,并观察随着时间的推移,我的进程的内存消耗,它将稳步增长到大约2GB,然后突然下降到大约100 my,因为GC进行其收集运行,然后它将再次增长。GC运行之间的时间可能有所不同,根本没有可预见性。
由于这些字符串中有很多是相同的(例如键Response、Status等)以及已知的值,比如OK和Fail,所以我可以使用字符串实习生来减少使用,如下所示:
// In the state-machine parser after having read a Key name:
String key = stringBuilder.ToString();
key = String.Intern( key );
// etc... after reading value
messageDictionary.Add( key, value );问题是,我看到了一个额外优化的空间:sb.ToString()将分配一个新的字符串实例,该实例将用于实习;其次:实习字符串将持续应用程序域的生命周期,不幸的是,有些密钥不会被重用,实际上会浪费内存,比如我的协议示例中的Foo123。
我认为一个解决方案是不使用字符串实习生,而是有一个包含static readonly字符串字段的类,这些字段是已知的键,然后使用普通的、非实习生的字符串--这最终会成为GC的结果,因此不会冒险用一次性字符串填充字符串实习生池。然后,我将StringBuilder实例与这些已知字符串进行比较,如果是,使用它们而不是调用sb.ToString(),从而跳过另一个字符串分配。
然而,如果我确实选择实习生每个字符串,实习生池将继续增长,不幸的是,.NET似乎没有一个字符串池的.Chlorinate()方法,如果我继续使用String.Intern方法,是否有任何方法从实习生池中删除单用途字符串,还是使用我自己的静态只读字符串实例更好?
发布于 2014-11-06 09:46:51
实习在这里不会有帮助,因为你所列举的理由。这实际上会使事情变得更糟,因为被拘留的字符串不再受垃圾收集的约束。不,没有方法从池中删除内部字符串。
您已经描述了GC做了GC设计要做的事情,所以我不太清楚您是否真的有问题。采用实习将意味着用垃圾收集(这不是问题)来换取不断增长的内存需求(这是一个问题)。
如果您担心GC的运行频率不足以将您的内存消耗控制在某个阈值以下,那么您可能会考虑监视您的内存使用情况,并在达到该阈值时调用GC.Collect()。
如果GC的行为模式实际上导致了问题(除了看起来很奇怪),那么您可能希望尝试从默认的“工作站”GC模式切换到“服务器”GC模式,因为它们是不同的调优方式。(不过,我也不认为你真的有问题。)
这两页介绍了一些不同之处:
collection
http://blogs.msdn.com/b/dotnet/archive/2012/07/20/the-net-framework-4-5-includes-new-garbage-collector-enhancements-for-client-and-server-apps.aspx
但是请注意,实际的差异随着框架的每个版本而变化,因为负责这件事的人总是在学习和改进。
GC模式由app配置控制:
http://msdn.microsoft.com/en-us/library/cc165011(v=office.11).aspx
<configuration
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration> 您可能还会发现这个故障排除指南很有用,或者至少很有趣:
TooMuchMemory
https://stackoverflow.com/questions/26524687
复制相似问题