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

Go语言调用http.Client.Do方法引发内存泄漏该如何修复

问题根源

内存泄漏的核心原因是每次调用getAPIData函数都重新实例化http.Client:

  • http.Client本身是线程安全的,设计定位就是全局复用的对象,内部会维护TCP连接池来复用HTTP连接
  • 每次新建http.Client都会生成独立的连接池,旧Client对应的连接、缓冲等资源无法被及时回收,长期运行就会出现内存持续上涨的情况

修复方案

核心修改

将http.Client提取为全局实例,初始化一次后所有请求共用即可,不需要每次请求都新建。

可选规范优化

Go 1.16及以上版本中,ioutil.ReadAll已经被废弃,可以替换为标准库io包下的io.ReadAll,该修改不影响内存泄漏问题,属于写法规范优化。

修复后完整代码

package main

import (
	"fmt"
	"io"
	"net/http"
	"runtime"
	"time"
)

// 全局复用http.Client
var client = &http.Client{Timeout: 3 * time.Second}

func getAPIData() (string, error) {
	req, err := http.NewRequest("GET", "https://google.com/", nil)
	if err != nil {
		return "", err
	}
	req.Header.Add("User-Agent", "Mozilla/5.0")

	resp, err := client.Do(req)
	if err != nil {
		fmt.Println(err.Error())
		return "", err
	}
	defer resp.Body.Close()

	bytes, err2 := io.ReadAll(resp.Body)
	if err2 != nil {
		fmt.Println(err2.Error())
		return "", err2
	}
	return string(bytes), nil
}

func PrintMemUsage() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)

	fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
	fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
	fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
	fmt.Printf("\tNumGC = %v\n", m.NumGC)
}

func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}
func main() {
	for range time.Tick(5 * time.Second) {
		_, _ = getAPIData()
		PrintMemUsage()
	}
}

修改后运行可以观察到Alloc内存会在GC后稳定在固定区间,不会持续上涨。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 19:18:03