[golang]golang time.After内存泄露问题分析
无意中看到一篇文章说,当在for循环里使用select + time.After的组合时会产生内存泄露,于是进行了复现和验证,以此记录
内存泄露复现
问题复现测试代码如下所示:
package main import (
"time"
) func main() {
ch := make(chan int, ) go func() {
var i =
for {
i++
ch <- i
}
}() for {
select {
case x := <- ch:
println(x)
case <- time.After( * time.Minute):
println(time.Now().Unix())
}
}
}
执行go run test_time.go,通过top命令,我们可以看到该小程序的内存一直飙升,一小会就能占用3G多内存,如下图:

原因分析
在for循环每次select的时候,都会实例化一个一个新的定时器。该定时器在3分钟后,才会被激活,但是激活后已经跟select无引用关系,被gc给清理掉。
换句话说,被遗弃的time.After定时任务还是在时间堆里面,定时任务未到期之前,是不会被gc清理的。
也就是说每次循环实例化的新定时器对象需要3分钟才会可能被GC清理掉,如果我们把上面复现代码中的3分钟改小点,改成10秒钟,通过top命令会发现大概10秒钟后,该程序占用的内存增长到1.05G后基本上就不增长了
原理验证
通过runtime.MemStats可以看到程序中产生的对象数量,我们可以验证一下上面的原理
验证代码如下所示:
package main import (
"time"
"runtime"
"fmt"
) func main() {
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
fmt.Println("before, have", runtime.NumGoroutine(), "goroutines,", ms.Alloc, "bytes allocated", ms.HeapObjects, "heap object")
for i := ; i < 1000000; i++ {
time.After( * time.Minute)
}
runtime.GC()
runtime.ReadMemStats(&ms)
fmt.Println("after, have", runtime.NumGoroutine(), "goroutines,", ms.Alloc, "bytes allocated", ms.HeapObjects, "heap object") time.Sleep( * time.Second)
runtime.GC()
runtime.ReadMemStats(&ms)
fmt.Println("after 10sec, have", runtime.NumGoroutine(), "goroutines,", ms.Alloc, "bytes allocated", ms.HeapObjects, "heap object") time.Sleep( * time.Minute)
runtime.GC()
runtime.ReadMemStats(&ms)
fmt.Println("after 3min, have", runtime.NumGoroutine(), "goroutines,", ms.Alloc, "bytes allocated", ms.HeapObjects, "heap object")
}
验证结果如下图所示:

从图中可以看出,实例中循环跑完后,创建了3000152个对象,由于每个time定时器设置的为3分钟,在3分钟后,可以看到对象都被GC回收,只剩153个对象,从而验证了,time.After定时器在定时任务到达之前,会一直存在于时间堆中,不会释放资源,直到定时任务时间到达后才会释放资源。
问题解决
综上,在go代码中,在for循环里不要使用select + time.After的组合,可以使用time.NewTimer替代
示例代码如下所示:
package main import (
"time"
) func main() {
ch := make(chan int, ) go func() {
for {
ch <-
}
}() idleDuration := * time.Minute
idleDelay := time.NewTimer(idleDuration)
defer idleDelay.Stop() for {
idleDelay.Reset(idleDuration) select {
case x := <- ch:
println(x)
case <-idleDelay.C:
return
}
}
}
结果如下图所示:

从图中可以看到该程序的内存不会再一直增长
参考文章
(1) 分析golang time.After引起内存暴增OOM问题
[golang]golang time.After内存泄露问题分析的更多相关文章
- 五、jdk工具之jmap(java memory map)、 mat之四--结合mat对内存泄露的分析、jhat之二--结合jmap生成的dump结果在浏览器上展示
目录 一.jdk工具之jps(JVM Process Status Tools)命令使用 二.jdk命令之javah命令(C Header and Stub File Generator) 三.jdk ...
- (转)专项:Android 内存泄露实践分析
今天看到一篇关于Android 内存泄露实践分析的文章,感觉不错,讲的还算详细,mark到这里. 原文发表于:Testerhome: 作者:ycwdaaaa ; 原文链接:https://teste ...
- 查看w3wp进程占用的内存及.NET内存泄露,死锁分析
一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...
- 关于Android 的内存泄露及分析
一. Android的内存机制Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似.程序员通过new为对象分配内存,所有对象在java堆内分配空间:然而对象的释 ...
- 查看w3wp进程占用的内存及.NET内存泄露,死锁分析--转载
一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...
- ThreadLocal是否会引发内存泄露的分析(转)
这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...
- ThreadLocal是否会引发内存泄露的分析 good
这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...
- 关于Android 的内存泄露及分析(转)
一. Android的内存机制Android的程序由Java语言编写,所以Android的内存管理与Java的内存管理相似.程序员通过new为对象分配内存,所有对象在java堆内分配空间:然而对象的释 ...
- 小题大做 | Handler内存泄露全面分析
前言 嗨,大家好,问大家一个"简单"的问题: Handler内存泄露的原因是什么? 你会怎么答呢? 这是错误的回答 有的朋友看到这个题表示,就这?太简单了吧. "内部类持 ...
随机推荐
- 数据源Source 目标Target
数据源Source-目标Target 数据源实现INotifyPropertyChanged接口,实现“通知”目标实现依赖属性 举例 后台的数据源,实现INotifyPropertyChanged接口 ...
- IOS开发之delegate和Notification的区别
delegate针对one-to-one关系,并且reciever可以返回值给sender: notification 可以针对one-to-one/many/none,reciever无法返回值给s ...
- Linux学习之“fork函数”
n返回值: fork函数调用一次,但是返回两次:在子进程中返回0,在父进程中返回子进程ID,出错返回-1.通过返回值,可以确定是在父进程还是子进程中. n子进程和父进程继续执行fork调用之后的指令. ...
- /\B(?=(?:\d{3})+$)/g 一条令人费解的正则表达式
网上浏览博客看到要用JavaScript正则表达式解决一个功能, 要在数字中间插入逗号, 用来表示书面的金额写法. JS代码是这样子的 let test1 = '1234567890' let for ...
- 高启全:长江存储自主3D NAND,DRAM研发欢迎美光一起加入(千秋大业,慢慢做)
台湾DRAM教父高启全转战大陆紫光集团操盘存储器大计划超过1年,日前晋升长江存储的执行董事.代行董事长,接受DIGITIMES独家专访公开未来规划:他指出,已齐聚500名研发人员在武汉投入3D NAN ...
- SSL Converter & Formats
https://www.sslshopper.com/ssl-converter.html PEM Format The PEM format is the most common format th ...
- 使用QPainter的drawPixmap()绘制多幅图片 good
众所周知,使用QLabel的setPixmap()就可以将图片显示出来,做视屏解码后显示也可以如此.但是为何我今天还要费力使用基函数drawPixmap()来做绘图?理由有这么些吧: 1.使用QLab ...
- log4j-slf4j 典型用例
一.maven 配置 <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j ...
- BI-学习之 新概念介绍
什么是统一维度模型 层次结构.级别.成员和度量值 什么是MDX MDX与SQL的区别 什么是数据仓库 什么是OLAP数据分析引擎 BI企业级解决方案 什么是统一维度模型 维度(dimension)是描 ...
- DUI-Windows消息机制要点(34篇)
[隐藏] 1窗口过程概念 2消息类型 2.1系统定义消息 2.1.1窗口消息 2.1.2命令消息 2.1.3控件通知消息 2.1.4程序定义消息 3消息队列 3.1系统消息队列 3.2线程消息队列 4 ...