在 .NET 中的多线程设置(例如网络服务器)中,我通常会尽量避免创建占用更多 85KB 的连续内存块,因为这可能最终会出现在大型对象堆上,这可能会导致内存问题。
我的一位开发人员正在使用循环写入Response
. ,除了在循环结束时OutputStream
没有ing。Flush
我认为不在Flush
循环中可能会导致内存问题是否正确?我怎么能证明这一点?
在 .NET 中的多线程设置(例如网络服务器)中,我通常会尽量避免创建占用更多 85KB 的连续内存块,因为这可能最终会出现在大型对象堆上,这可能会导致内存问题。
我的一位开发人员正在使用循环写入Response
. ,除了在循环结束时OutputStream
没有ing。Flush
我认为不在Flush
循环中可能会导致内存问题是否正确?我怎么能证明这一点?
这取决于正在使用的流的实现细节。来自Stream 基类的 MSDN 文档
流是字节序列的抽象,例如文件、输入/输出设备、进程间通信管道或 TCP/IP 套接字。Stream 类及其派生类提供了这些不同类型的输入和输出的通用视图,并将程序员与操作系统和底层设备的具体细节隔离开来。
如果该流的实现者没有就如何处理多个后续Write
调用留下任何额外的指导,我们应该假设它为您处理了这些刷新细节。
我假设你觉得这个答案有点令人失望,所以深入挖掘一下。正如您所说,您的同事正在使用Response.OutputStream
让我们看看该属性的底层实现是什么。
get
{
if (!this.UsingHttpWriter)
{
throw new HttpException(SR.GetString("OutputStream_NotAvail"));
}
return this._httpWriter.OutputStream;
}
所以它使用Stream
from something in _httpWriter
。结果证明该字段包含对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();
}
}
HttpResponseUnmanagedBufferElement
正如您所看到的,byte[] 数据正在被传递给一个方法,该方法在将字节复制到内存的帮助下进一步复制和存储数据,并使用Marshal.Copy
非托管内存的缓冲区。该内存似乎被分配在大约 16K 的块中,用于集成管道,其余大约为 31K。
有了这个,我不希望 Stream 分配这么多内存,以至于它的内部结构最终会出现在 LOH 上,因为从外观上看,它只会生成托管 -> 非托管内存副本。
将您的想法留给我们,以便定期调用Flush
。有这个HttpResponseStream
实现:
public override void Flush()
{
this._writer.Flush();
}
哪里_writer
是较早发现的HttpWriter
。它的实现是
public override void Flush()
{
}
没错,调用flush只会浪费CPU周期。尽管MSDN中的文档很有希望,但它不会帮助流更快地清除其缓冲区。