改变结构体中的 slice 的问题

以下这段代码来自 fasthttp 中的 workerpool.go

func (wp *workerPool) getCh() *workerChan {
    var ch *workerChan
    createWorker := false

    wp.lock.Lock()
    ready := wp.ready
    n := len(ready) - 1
    if n < 0 {
        if wp.workersCount < wp.MaxWorkersCount {
            createWorker = true
            wp.workersCount++
        }
    } else {
        ch = ready[n]
        ready[n] = nil
        wp.ready = ready[:n]
    }
    wp.lock.Unlock()

    if ch == nil {
        if !createWorker {
            return nil
        }
        vch := wp.workerChanPool.Get()
        if vch == nil {
            vch = &workerChan{
                ch: make(chan net.Conn, workerChanCap),
            }
        }
        ch = vch.(*workerChan)
        go func() {
            wp.workerFunc(ch)
            wp.workerChanPool.Put(vch)
        }()
    }
    return ch
}

第9行:ready = wp.ready, 第18行和第19行,取出最后一个元素后,将最后一个元素设为nil,并删除最后一个元素。 我的问题是,为什么要将最后一个元素设为nil,为什么不直接用wp.ready = wp.ready[:n]?

已邀请:

simple - 既要有梦想,又要有实力

赞同来自: killernova modood

这个是一个比较常见的内存泄漏的问题(不是假象),wp.ready底层存储是一个连续的内存块,wp.ready = wp.ready[:n]之后,底层的内存块大小并没有改变,只是赋值语句之后通过wp.ready无法再访问赋值之前wp.ready的最后一个元素,但这个最后的元素还在指向了一个workerChan, 也就是说有一个已经不再使用的指针始终指向workerChan, 导致这个workerChan的堆内存无法被GC掉。 对所有有GC的语言,都应该注意这种情况。

lrita

赞同来自:

跟gc扫描有关,否则会造成内存泄露的假象

要回复问题请先登录注册