3

在 .NET 中的多线程设置(例如网络服务器)中,我通常会尽量避免创建占用更多 85KB 的连续内存块,因为这可能最终会出现在大型对象堆上,这可能会导致内存问题。

我的一位开发人员正在使用循环写入Response. ,除了在循环结束时OutputStream没有ing。Flush

我认为不在Flush循环中可能会导致内存问题是否正确?我怎么能证明这一点?

4

1 回答 1

1

这取决于正在使用的流的实现细节。来自Stream 基类的 MSDN 文档

流是字节序列的抽象,例如文件、输入/输出设备、进程间通信管道或 TCP/IP 套接字。Stream 类及其派生类提供了这些不同类型的输入和输出的通用视图,并将程序员与操作系统和底层设备的具体细节隔离开来。

如果该流的实现者没有就如何处理多个后续Write调用留下任何额外的指导,我们应该假设它为您处理了这些刷新细节。

我假设你觉得这个答案有点令人失望,所以深入挖掘一下。正如您所说,您的同事正在使用Response.OutputStream让我们看看该属性的底层实现是什么。

get
{
    if (!this.UsingHttpWriter)
    {
        throw new HttpException(SR.GetString("OutputStream_NotAvail"));
    }
    return this._httpWriter.OutputStream;
}

所以它使用Streamfrom 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中的文档很有希望,但它不会帮助流更快地清除其缓冲区。

于 2016-07-18T20:13:47.787 回答