loops - 如果永远运行,ticker.C 是否会泄漏内存?

标签 loops go memory-leaks

我在 stack overflow 中搜索过类似的东西,但找不到我要找的东西。如果这是一个明显的错误,我深表歉意,因为我最近才开始用 Go 编写代码,但我很感激任何提前的解释。 我目前有一个范围超过 *Ticker 值的 go 例程。 现在这个 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 ...
}

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

我感谢对此的任何帮助/解释。谢谢。

最佳答案

正如@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

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

同样酷的是,您可以生成程序的 graphviz 图表,以便可视化和跟踪当前内存使用情况(或内存分配):

enter image description here


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

我写了一些关于它的内容:

还有很多令人惊叹的资源,其中两个是:

关于loops - 如果永远运行,ticker.C 是否会泄漏内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55243071/

相关文章:

r - 使用循环组合向量

variables - 我应该什么时候初始化 Golang 变量

compiler-construction - 在 Windows 中编译 Go 文件?

c++ - 寻求内存泄漏方面的帮助 - 拥有多线程队列、字符缓冲区和结构

java - com.sun.imageio.plugins.jpeg.JPEGImageReader 泄漏

javascript - PHP MySQL JS AJAX - 循环问题

java - EnumSet 可以按书面顺序返回值吗?

c - 赋值给数组类型为 ch= ch+(s[i]) 的表达式;

go - 从 reflect.Type 中删除指针

scala - 如何防止 Scala Futures 造成内存泄漏