可以连续写入流而不刷新强制其内容到大型对象堆上
本文关键字:大型 对象 连续 刷新 | 更新日期: 2023-09-27 17:57:14
在多线程设置(如 Web 服务器)中,在 .NET 中,我通常尽量避免创建占用更多 85KB 的连续内存块,因为这最终可能会出现在大型对象堆上,这可能会导致内存问题。
我的一位开发人员同事正在使用循环写入Response
。 OutputStream
,除了在循环结束时外,没有Flush
。
我是否正确认为不Flush
循环会导致内存问题? 我怎么能证明这一点?
这取决于所使用的流的实现细节。从流基类上的 MSDN 文档
流是字节序列的抽象,例如文件、输入/输出设备、进程间通信管道或 TCP/IP 套接字。Stream 类及其派生类提供这些不同类型的输入和输出的通用视图,并将程序员与操作系统和基础设备的特定详细信息隔离开来。
如果该流的实现者没有留下任何关于如何处理多个后续Write
调用的额外指导,我们应该假设它为您处理这些刷新详细信息。
我想你觉得这个答案有点令人失望,所以深入挖掘一下。正如您所说,您的同事正在使用Response.OutputStream
让我们看看该属性的基础实现是什么。
get
{
if (!this.UsingHttpWriter)
{
throw new HttpException(SR.GetString("OutputStream_NotAvail"));
}
return this._httpWriter.OutputStream;
}
所以它正在使用_httpWriter
中某些东西的Stream
.该字段原来包含对HttpWriter
实例的引用。它是OutputStream
属性在构造函数中初始化:
this._stream = new HttpResponseStream(this);
类HttpResponseStream
是内部的,但我们可以使用 ILSpy 来撬开它。它的Write
方法将实现推迟到这个HttpWriter的方法:
internal void WriteFromStream(byte[] data, int offset, int size)
{
if (this._charBufferLength != this._charBufferFree)
{
this.FlushCharBuffer(true);
}
this.BufferData(data, offset, size, true);
if (!this._responseBufferingOn)
{
this._response.Flush();
}
}
如您所见,byte[] 数据正在传递给一个方法,该方法在帮助HttpResponseUnmanagedBufferElement
的帮助下进一步复制和存储数据,该方法将字节复制到内存中,并Marshal.Copy
到非托管内存的缓冲区。该内存似乎以大约 16K 的块分配给集成管道,其余的大约 31K 的块。
因此,我不希望 Stream 分配太多内存,以至于其内部结构最终位于 LOH 上,因为从外观上看,它只会制作托管>非托管内存副本。
让我们知道您的想法,定期打电话给循环中的Flush
。HttpResponseStream
具有以下实现:
public override void Flush()
{
this._writer.Flush();
}
其中_writer
是较早发现的HttpWriter
。它的实现是
public override void Flush()
{
}
没错,调用刷新只会浪费 CPU 周期。它不会帮助流更快地清除其缓冲区,尽管 MSDN 中有很有希望的文档。