golang 关闭gc 并手动gc_Golang 防内存泄漏编码原则

本文围绕Go编程中内存泄漏问题展开。介绍了内存泄漏的表现,如打压力后内存不降低;指出top不能实时反映程序内存占用,还说明了Go内存管理机制。给出查看内存使用信息的方法,同时阐述了避免内存泄漏的原则,如生产者关闭channel、利用channel广播取消动作等。

(给Go开发大全加星标)

来源:zmlgo
https://www.cnblogs.com/share-ideas/p/11365511.html

【导读】go 编程中,如果写法不当,可能引发内存泄漏。本文介绍了一些 coding 原则和详细示例。

1、给系统打压力,内存占用增大,但停止打压后,内存不能降低,则可能有内存泄漏。

2、top不能实时反映程序占用内存,因Go向系统申请内存不使用后,并不立即归还系统。


3、程序占用系统内存、Go的堆内存、实际使用内存:从系统申请的内存会在Go的内存池管理,整块的内存页,长时间不被访问并满足一定条件后,才归还给操作系统。又因为有GC,堆内存也不能代表内存占用,清理过之后剩下的,才是实际使用的内存。


4、调用runtime.ReadMemStats可以看到Go的内存使用信息。


5、使用go tool pprof -inuse_space http://127.0.0.1:6060/debug/pprof/heap?debug=2得到更细信息,其中HeapInuse为实际内存使用量。

6、第一条原则是,绝对不能由消费者关channel,因为向关闭的channel写数据会panic。正确的姿势是生产者写完所有数据后,关闭channel,消费者负责消费完channel里面的全部数据。

func produce(ch chan {    defer close(ch) // 生产者写完数据关闭channel    ch }func consume(ch chan T) {    for _ = range ch { // 消费者用for-range读完里面所有数据    }}ch := make(chan T)go produce(ch)consume(ch)

7、第二条原则是,利用关闭channel来广播取消动作,并可配合着WaitGroup类来使用。

func produce(ch chanchan struct{}) {    select {      case ch       case // 用select同时监听cancel动作    }}func consume(ch chan T, cancel chan struct{}) {    v :=     err := doSomeThing(v)    if err != nil {        close(cancel) // 能够通知所有produce退出        return    }}for i:=0; i<10; i++ {    go produce()}consume()

8、通过chann发信号来关闭协程。

func (m *TtlMap) clear() {    for {        select {        // 关闭        case             return        //定期清理...        }    }}

9、MapWarpper作为局部变量时,定义它的函数结束后,MapWarpper的生命周期已结束,Gc会将其回收。Gc回收MapWarpper时执行了onGarbageCollect()函数,将Ttlmap的clear协程关闭,进而将Ttlmap回收。

strcut TtlMap {    ...    stop chan bool}// 包裹定义struct MapWarpper {    *TtlMap}func New() *MapWarpper {    map := &TtlMap{        ...    }    go map.clear()    // 包一层    mw := &MapWarpper{map}        // 重点在此:设置被回收时操作    runtime.SetFinalizer(mw, onGarbageCollect)    return mw}

10、通过context包来避免内存泄漏。

func main() {    ctx, cancel := context.WithCancel(context.Background())     ch := func(ctx context.Context) chan int {        ch := make(chan int)        go func() {            for i := 0; ; i++ {                select {                case                     return                case ch                 }            }        } ()        return ch    }(ctx)     for v := range ch {        fmt.Println(v)        if v == 5 {            cancel()            break        }    }}

 - EOF -

推荐阅读(点击标题可打开)

1、用etcd做go-micro的服务发现

2、k8s调度的优先级及抢占机制源码分析

3、Golang 的 sync.Pool设计思路与原理

如果觉得本文不错,欢迎转发推荐给更多人。

47a83ddc616b9581cd4f991fb43870ac.png

分享、点赞和在看

支持我们分享更多好文章,谢谢!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值