[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内存泄露的原因是什么? 你会怎么答呢? 这是错误的回答 有的朋友看到这个题表示,就这?太简单了吧. "内部类持 ...
随机推荐
- WPF 动态绑定listview的列内容
Binding binding = new Binding(); binding.Path = new PropertyPath("State"); listViewState.D ...
- 图像滤镜艺术---Oilpaint油画滤镜
原文:图像滤镜艺术---Oilpaint油画滤镜 Oilpaint油画滤镜 图像油画效果实际上是将图像边缘产生一种朦胧,雾化的效果,同时,将一定的边缘模糊化,这样图像整体上看去像素与像素之间 ...
- 利用NPOI生成DOCX文档
首先安装NPOI控件: Install-Package NPOI 代码: using NPOI.OpenXmlFormats.Wordprocessing; using NPOI.XWPF.UserM ...
- sqlite查询问题,由字母大小写敏感引起
目前做的项目之前是用mysql,这是个错误的选择,因为本身并不是服务器-客户端模式的项目,而是一个CS架构项目,mysql这种需要较繁复配置的数据库并不合适.需要的应该是sqlite这类,内嵌的数据库 ...
- Windows下libevent C++封装类实现(为什么要使用封装好的网络库?)
题记 windows平台下对于服务器高并发的网络模型选型中,使用libevent是个不错的选择. 本文的背景基于:国内博客对于libevent大多介绍linux实现,大多是c语言的实现,Windows ...
- 浅谈Linux(Centos7.4)环境下NTP服务器的构建
一.软件环境 1.操作系统版本 [root@Geeklp201 etc]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core ...
- linux环境下使用百度云网盘
linux下经常需要备份一些文件到云端,现在能用的也就只有度娘的百度云网盘了,在github上发现一个挺好的项目,bypy,用来在linux下使用百度云. 项目地址:https://github.co ...
- 条款14:在资源管理类中小心copying行为
请牢记: 1.复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 2.普遍常见的RAII class copying行为是:抑制copyin ...
- centos安装最新版MySQL 8.0教程
这篇教程是通过yum方式安装的 安装依赖 yum install libaio wget -y 检查MYSQL是否已安装 yum list installed | grep mysql 如果有先卸载 ...
- java垃圾回收机制整理
一.垃圾回收器和finalize() java垃圾回收器只负责回收无用对象占据的内存资源.但是如果你的对象不是通过 new 创建的(所有的new 对象都往堆中开辟资源,在一个地方,方便清理/管理资源) ...