【问题标题】:Does ticker.C leak memory, if run forever?如果永远运行,ticker.C 是否会泄漏内存?
【发布时间】:2019-03-19 14:15:41
【问题描述】:

我已经在堆栈溢出中搜索了类似的内容,但找不到我正在寻找的确切内容。如果这是一个明显的错误,我深表歉意,因为我最近才开始用 Go 编写代码,但我感谢您提前做出的任何解释。 我目前有一个范围超过*Ticker 的值的例程。 现在这个 go 例程在我的程序处于活动状态的整个过程中运行,因为它会检查必要的更新。我开始意识到我的程序会随着时间的推移慢慢泄漏内存。跑步 20 到 30 小时后开始变得非常明显。

func (s *Server) checkForUpdates() { // go routine
    ticker := time.NewTicker(time.Minute * time.Duration(s.checkTime)) //x.checkTime = 2 minutes
    defer ticker.Stop()
    for t := range ticker.C { // will loop every 2 minutes
         fmt.Println("the update check happened at %d\n", t)
         // do the updates
    }
}

我将泄漏范围缩小到 go 例程,并阅读了一路的 Time can leak memory。确保在完成 go 例程后关闭您创建的 *Ticker。但是我的程序永远运行,直到我杀死它。所以这个 go 例程将永远运行,直到我决定停止程序。 我知道这可能很愚蠢,但我认为可能是t := range ticker.C 部分可能是问题所在。因为那个循环在我杀死之前永远不会停止。所以t 永远不会被释放。所以我认为:= 每次循环时都会重新声明变量?然后我循环到:

for _ = range ticker.C { // completely got rid of declaration of time.Time
   // do updates ...
}

到目前为止,它似乎正在工作......但我真的不明白为什么,或者它应该没有帮助,而且还有其他事情我做错了。

感谢任何帮助/解释。谢谢。

【问题讨论】:

  • 应用程序正在正确使用代码。如果泄漏出在这个 goroutine 中,那么问题出在// do updates
  • 欢迎来到 StackOverflow!您在循环中返回的值只是代码关闭的时间,它可能已分配在堆栈上,并且仅在一个循环迭代的持续时间内存在。它不能泄漏。股票代码,如果它意味着你的应用程序的生命周期,那么根据定义也不能泄漏。您能否详细说明是什么让您认为您有内存泄漏以及您如何将引用的代码识别为泄漏的来源?
  • 如果ticker导致内存泄漏,这意味着Go中有一个非常严重的错误,因为ticker本质上只是一个通道。
  • Go 附带了一个名为pprof 的下一级工具,它将通过显示使用的总内存和/或每个语句分配的总内存来帮助您跟踪程序中内存泄漏的确切来源。网上有大量关于如何使用它的博客文章(以及 golang.org 上的精彩文档)。我也试着解释一下medium.com/dm03514-tech-blog/…
  • defer reader.Close() 是直接从checkForUpdates 中的循环调用的吗?如果是这样,那就是问题所在。延迟调用在函数返回时执行。

标签: loops go memory-leaks


【解决方案1】:

正如@Cerise Limon 指出的那样,您的应用程序很可能在其执行的逻辑中泄漏了内存。为了准确查明什么是内存泄漏,您可以使用pprof 来显示语句使用的总内存。这是一种回答任何问题的方法,例如:

  • “应用程序的哪个部分在某个时间点使用的内存最多?”
  • “应用程序的哪个部分负责最多的内存分配?(以字节为单位)”
  • “应用程序的哪个部分(如果有)随着时间的推移而增长”
  • “给定语句/行在某个时间点使用了多少内存?”

启用 pprof 后,您可以使用以下方法获取内存配置文件:

$ curl http://localhost:8080/debug/pprof/heap > heap.0.pprof

然后您可以使用 cli 与配置文件交互:

$ go tool pprof pprof/heap.3.pprof
Local symbolization failed for main: open /tmp/go-build598947513/b001/exe/main: no such file or directory
Some binary filenames not available. Symbolization may be incomplete.
Try setting PPROF_BINARY_PATH to the search path for local binaries.
File: main
Type: inuse_space
Time: Jul 30, 2018 at 6:11pm (UTC)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) svg
Generating report in profile002.svg
(pprof) top20
Showing nodes accounting for 410.75MB, 99.03% of 414.77MB total
Dropped 10 nodes (cum <= 2.07MB)
      flat  flat%   sum%        cum   cum%
  408.97MB 98.60% 98.60%   408.97MB 98.60%  bytes.Repeat
    1.28MB  0.31% 98.91%   410.25MB 98.91%  main.(*RequestTracker).Track
    0.50MB  0.12% 99.03%   414.26MB 99.88%  net/http.(*conn).serve
         0     0% 99.03%   410.25MB 98.91%  main.main.func1
         0     0% 99.03%   410.25MB 98.91%  net/http.(*ServeMux).ServeHTTP
         0     0% 99.03%   410.25MB 98.91%  net/http.HandlerFunc.ServeHTTP

这将显示您的应用程序中正在使用多少内存以及哪些语句/行负责。

还有一点很酷的是,您可以生成程序的图形化图表,以便可视化和跟踪当前的内存使用情况(或内存分配):


网上有很多关于 pprof 的博客文章(包括标准文档)。

我写了一点:

还有很多神奇的资源,其中两个是:

【讨论】:

  • 感谢您提供的所有资源,将继续尝试 pprof!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-14
  • 1970-01-01
  • 2012-09-13
  • 2020-07-22
  • 2010-10-13
  • 2019-01-28
相关资源
最近更新 更多