Golang 内存泄漏问题和处理方法

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<- T) {

    defer close(ch) // 生产者写完数据关闭channel

    ch <- T{}

}

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 chan<- T, cancel chan struct{}) {

    select {

      case ch <- T{}:

      case <- cancel: // 用select同时监听cancel动作

    }

}

func consume(ch <-chan T, cancel chan struct{}) {

    v := <-ch

    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 <-m.stop:

            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 <- ctx.Done():
                    return
                case ch <- i:
                }
            }
        } ()
        return ch
    }(ctx)
 
    for v := range ch {
        fmt.Println(v)
        if v == 5 {
            cancel()
            break
        }
    }
}

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值