我们在ASP中每天都会遇到outofmemoryexception。Net 4.0网站。我们怀疑其中一个问题是LOH碎片,所以我们一直在研究代码更改,以更有效地分配内存。
例如,我们正在生成一个大字符串(2mb),我们希望返回给浏览器。分页数据不是一个选项。
是否更有效率?
- 在StringBuilder中构建字符串,然后对
Response.Write(bigString)
或 进行单个调用 - 通过对
Response.Write(smallString)
的重复调用来逐条写入字符串
如果我遵循选项1,那么我有一个大字符串占用LOH上的空间,然后被复制到响应对象的内部缓冲区。所以看起来我现在在LOH上有两个大块,至少暂时是这样。
如果我遵循选项2,那么我正在处理许多被垃圾收集的小字符串,并且只有LOH上的一个大块用于响应对象的缓冲区。
所以我觉得选项2更好。
我理解对了吗?
服务器有4gb内存,运行Windows 2003 32位。这是服务器上唯一运行的站点。所以每个进程有4gb的地址空间,但只有2gb是可用的。当虚拟字节达到1.8Gb时,我们开始出现OOM错误,然后我们回收网站,这解决了大约24小时的问题。私有字节在500-800mb之间。我认为问题不在于我们的物理内存快用完了。
在不了解实现的情况下,我的答案可能没有我希望的那么有帮助。不过我还是想试一试。
如果是我,我会使用两种策略:
- 利用硬盘空间,写入存储在服务器缓存目录中的文本文件(假设只有一个web服务器)
- 使用老式的Server.Execute("~/filename.txt");将文本文件内容输出到页面上。
答案可能取决于您如何构建"大的2Mb字符串"。例如,最重要的是使用StringBuilder类来连接内容,例如
System.Text.StringBuilder sb = new System.Text.StringBuilder(256*1024);
sb.AppendText("some text");
sb.AppendText(myObject.name);
sb.AppendText("more text");
Response.Write(sb.ToString());
和不使用这样的字符串连接:
myString += "some text";
myString += myObject.name;
myString += "more text";
如果您使用后一种方法,我预计您可能会为了创建2Mb的字符串而消耗GB的内存,并不断与垃圾收集器进行斗争。
当然,写入Response对象可能会胜过这两种技术,但是YMMV.