为了账号安全,请及时绑定邮箱和手机立即绑定

在 for 循环中使用数据库连接时出现内存泄漏

在 for 循环中使用数据库连接时出现内存泄漏

Go
萧十郎 2023-08-14 16:56:28
我正在尝试在无限 for 循环中连续查询 Postgres 数据库。但是,查询似乎没有关闭,垃圾收集器可能无法工作,并且我面临内存分配问题。脚本设计如下:在func main()我声明一个全局数据库连接。然后执行func checkCross(...)其中包含 for 循环,每次迭代都会执行该循环,func importPrices(...)然后从数据库导入行。import (    "database/sql"    _"github.com/lib/pq"    "runtime"    )var db *sql.DBfunc main() {    var err error    psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+" dbname=%s password=%s ", host, port, user, dbname, password)    //connection    db, err = sql.Open("postgres", psqlInfo)    if err != nil {        log.Fatal(err)    }    defer db.Close()    checkCross("EUR_USD")    ...函数 checkCross(...)   func checkCross(instrument string) {    for i := 1; i < 4; i++ {            rawData, _ := importPrices(instrument)            var mem runtime.MemStats            runtime.ReadMemStats(&mem)            fmt.Printf("alloc [%v] \t heapAlloc [%v] \n", mem.Alloc, mem.HeapAlloc)            ...        }函数导入价格(...)func importPrices(instrument string) ([]float64, []time.Time) {    var price_ float64    var date_ time.Time    price := make([]float64, 10000000)    date := make([]time.Time, 10000000)    queryCommand := fmt.Sprintf("SELECT * FROM table where instrument = '%[1]v' ORDER BY 1 ASC;", instrument)    rows, err := db.Query(queryCommand)    if err != nil {        log.Fatal(err)    }    //scan from db    z := 0    for rows.Next() {        err := rows.Scan(&date_, &price_)        if err != nil {            log.Fatal(err)        }        price[z] = price_        date[z] = date_        z+=1    }    price = price[:z]     date = date[:z]     if err := rows.Err(); err != nil {        log.Fatal(err)    }    rows.Close()    return price, date输出alloc [321664064]        heapAlloc [321664064] alloc [641723264]        heapAlloc [641723264] alloc [961781984]        heapAlloc [961781984]您能否指导我的代码或方法中的问题出在哪里?rows.Close()我读过一些文章,他们建议在 for 循环中使用,defer rows.Close()但这个解决方案不起作用。
查看完整描述

1 回答

?
守着一只汪

TA贡献1872条经验 获得超3个赞

您在每次调用时分配两个 10M 元素的切片(float648 字节并且更大) 。time.TimeimportPrices

当然,这些切片中的大多数最终都会变成垃圾(据说,您用从 返回的那两个切片覆盖了一些变量importPrices),但这些垃圾会自然浮动,直到为您的程序提供支持的 Go 运行时决定收集它。在此之前,内存消耗将会增加。

理解该语言的两种“标准”实现(您应该使用其中一种)功能扫描GC 与主程序流并行工作是至关重要的。换句话说,当程序丢失对已分配内存块的最后一个实时引用时,该块占用的内存在那一刻不会发生任何事情- 它必须等到 GC 找到它并进行收集。这种情况发生的确切时间大多是无法预测的。Go 具有复杂的动态算法来调整GC 的速度,从而在收集垃圾所花费的 CPU 周期数量和让内存消耗增长之间取得一定的平衡。

对于当前的问题,通常的方法是简单地重用迭代之间分配的内存。也就是说,在调用之前预先分配切片importPrices,将它们传递到那里,然后将它们重置为零长度,然后再次传递它们。


查看完整回答
反对 回复 2023-08-14
  • 1 回答
  • 0 关注
  • 89 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信