在 for 循环中使用 db 连接时内存泄漏

我正在尝试在无限 for 循环中连续查询 Postgres 数据库。但是,查询似乎没有关闭,垃圾收集器可能无法正常工作,并且我面临内存分配问题。


脚本设计如下:


在func main()我声明一个全局数据库连接。然后执行func checkCross(...)which 包含 for 循环,每次迭代执行func importPrices(...)which 依次从数据库中导入行。


import (

    "database/sql"

    _"github.com/lib/pq"

    "runtime"

    )



var db *sql.DB


func 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()但这个解决方案不起作用。


慕容3067478
浏览 156回答 1
1回答

临摹微笑

在每次float64调用.time.TimeimportPrices当然,这些切片中的大多数最终都会变成垃圾(假设您用从 中返回的这两个切片覆盖了一些变量importPrices),但是这些垃圾会自然浮动,直到为您的程序提供支持的 Go 运行时决定收集它。在此之前,内存消耗将会增长。了解该语言的两种“标准”实现(您应该使用其中一种)具有与主程序流程并行工作的扫描GC 功能至关重要。换句话说,当程序丢失对已分配内存块的最后一个实时引用时,就在那一刻,该块占用的内存不会发生任何事情——它必须等到 GC 找到它然后收集它。发生这种情况的确切时间几乎是不可预测的。Go 采用复杂的动态算法来调整 GC 的速度,从而在收集垃圾所花费的 CPU 周期数量和让内存消耗增长之间取得某种平衡。对于手头的问题,通常的方法是在迭代之间简单地重用分配的内存。也就是说,在调用之前先分配切片importPrices,将它们传递到那里,然后将它们重置为零长度,然后再次传递它们。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go