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

Posted share-ideas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 := &MapWarppermap
    
    // 重点在此:设置被回收时操作
    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
        
    

 

以上是关于Golang内存泄漏问题和处理方法的主要内容,如果未能解决你的问题,请参考以下文章

排查内存泄漏最简单和直观的方法

golang:快来抓住让我内存泄漏的“真凶”!

golang读取XML内存泄漏?

前端vue项目内存泄漏排查总结

手撸golang GO与微服务 ChatServer之4 内存泄漏

怎么排查这些内存泄漏