You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CopyTo向HttpWebRequest流写入数据引发内存持续增长问题排查

问题分析与解决方案

是不是内存泄漏?

这不属于严格意义上的内存泄漏,更可能是未正确释放托管/非托管资源,或是HttpWebRequest相关连接池、请求资源未及时回收导致的内存持续增长。

核心修复步骤

1. 完整释放HttpWebRequest及响应资源

你的代码仅释放了请求流,但未处理HttpWebRequest本身和响应对象,这会导致大量资源滞留。必须用using包裹所有实现IDisposable的对象:

void SendToOtherServer(Stream fileContents)
{
    using (HttpWebRequest request = (HttpWebRequest)WebRequest.Create("the other server address"))
    {
        request.Method = "POST"; // 务必设置请求方法
        // 若目标服务器支持,可关闭Expect100Continue减少交互开销
        // ServicePointManager.Expect100Continue = false;

        using (Stream destStream = request.GetRequestStream())
        {
            // 显式设置CopyTo缓冲区大小,避免一次性分配过大内存
            fileContents.CopyTo(destStream, 81920); // 80KB缓冲区,可根据业务调整
        }

        // 必须处理响应,否则连接无法回收到连接池
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            using (Stream responseStream = response.GetResponseStream())
            {
                // 读取响应流(即使不需要内容),确保连接资源释放
                responseStream.CopyTo(Stream.Null);
            }
        }
    }
}

2. 不要手动释放传入的fileContents

fileContents是WCF框架传入的流,由框架负责生命周期管理。你之前用using包裹它会提前释放流,可能导致WCF后续处理异常,直接移除该using即可。

3. 优化HttpWebRequest连接池配置

默认ServicePointManager.DefaultConnectionLimit仅为2,大量并发请求会导致连接排队、资源滞留。在应用启动时(如Global.asax的Application_Start)设置合理值:

ServicePointManager.DefaultConnectionLimit = Environment.ProcessorCount * 10; // 根据服务器配置调整

4. 异步场景的资源释放(若使用BeginGetResponse)

如果用异步方式发送请求,务必在回调中完整释放响应及流资源:

void SendAsync(Stream fileContents)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("the other server address");
    request.Method = "POST";
    request.BeginGetRequestStream(asyncResult =>
    {
        try
        {
            using (Stream destStream = request.EndGetRequestStream(asyncResult))
            {
                fileContents.CopyTo(destStream, 81920);
            }
            request.BeginGetResponse(responseResult =>
            {
                try
                {
                    using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(responseResult))
                    using (Stream responseStream = response.GetResponseStream())
                    {
                        responseStream.CopyTo(Stream.Null);
                    }
                }
                catch (WebException ex)
                {
                    // 处理异常,同时释放错误响应
                    if (ex.Response != null)
                    {
                        ((HttpWebResponse)ex.Response).Dispose();
                    }
                }
                finally
                {
                    request.Dispose();
                }
            }, null);
        }
        catch
        {
            request.Dispose();
            throw;
        }
    }, null);
}

为什么强制GC没用还变慢?

手动调用GC.Collect()会触发全量垃圾回收,暂停所有线程执行,导致性能急剧下降。正确释放资源后,GC会自动在合适时机回收托管内存,无需手动干预。

内容的提问来源于stack exchange,提问作者Programmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 22:15:00