【发布时间】:2011-05-01 21:59:51
【问题描述】:
我有一个通过基于HttpTransport 的自定义绑定公开的自托管WCF 服务(v4 框架)。绑定使用自定义的MessageEncoder,它几乎是BinaryMessageEncoder,并添加了 gzip 压缩功能。
Silverlight 和 Windows 客户端使用 Web 服务。
问题:在某些情况下,服务必须返回非常大的对象,并且在响应多个并发请求时偶尔会抛出 OutOfMemory 异常(即使任务管理器报告该进程约为 600 Mb)。异常发生在自定义编码器中,当消息即将被压缩时,但我相信这只是一个症状而不是原因。异常声明“未能分配 x Mb”,其中 x 为 16、32 或 64,而不是一个过大的数量 - 因此,我相信在此之前其他一些东西已经使该过程接近某个限制。
服务端点定义如下:
var transport = new HttpTransportBindingElement(); // quotas omitted for simplicity
var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity
var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport);
然后我做了一个实验:我将TransferMode从Buffered更改为StreamedResponse(并相应地修改了客户端)。这是新的服务定义:
var transport = new HttpTransportBindingElement()
{
TransferMode = TransferMode.StreamedResponse // <-- this is the only change
};
var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity
var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport);
神奇的是,不再有 OutOfMemory 异常。对于小消息,该服务有点慢,但随着消息大小的增长,差异会越来越小。 行为(速度和 OutOfMemory 异常)是可重现的,我对这两种配置进行了几次测试,这些结果是一致的。
问题解决了,但是:我无法解释自己这里发生了什么。令我惊讶的是我没有以任何方式更改合同。 IE。我没有像您通常对流式消息那样使用单个 Stream 参数等创建合同。我仍在使用具有相同 DataContract 和 DataMember 属性的复杂类。 我只是修改了端点,仅此而已。
我认为设置 TransferMode 只是为正确形成的合同启用流式传输的一种方式,但显然不止于此。
任何人都可以解释当您更改 TransferMode 时实际发生了什么?
【问题讨论】:
-
附言。我知道这个问题stackoverflow.com/questions/2312408 很相似,但没有得到答案(也许有更多细节会更容易)
标签: c# .net silverlight wcf