Golang中的切片与GC


本文摘自网络,作者,侵删。

今天再看 timer 源码的时候,在函数 clearDeletedTimers() 里看到一段对切片的处理代码,实现目的就是对一个切片内容进行缩容。

// src/runtime/time.go

// The caller must have locked the timers for pp.
func clearDeletedTimers(pp *p) {
    timers := pp.timers
    ......
    // 对无用的切片元素赋值 nil
    for i := to; i < len(timers); i++ {
        timers[i] = nil
    }

    atomic.Xadd(&pp.deletedTimers, -cdel)
    atomic.Xadd(&pp.numTimers, -cdel)
    atomic.Xadd(&pp.adjustTimers, -cearlier)

    timers = timers[:to]
    pp.timers = timers
    updateTimer0When(pp)

    ......
}

to 变量指新切片的长度, len(timers)指原来切片的长度。

这里在其进行 timers = timers[:to] 操作前,先是将 to 数组索引后的值进行了赋值 nil。按照我们平时用用法,是没有必要执行这一步的?那为什么这里要加这一步呢,其实这里与GC 有关?

在日常开发中很少注意到这个细节,虽然最终实现的结果是一样的,但如果考虑GC的话,差别可就大多了。

假如这里不进行赋值nil 的话,结果是没有问题的,但我们知道slice是底层是由三部分组成的。

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

slice.array 字段是一个指向底层数组的指针,这里函数的参数 pp 是指 GPM 中的 P 结构体,pp.timers 字段类型为 timers []*timer

一个应用程序会长时间处于运行状态,当GC执行的时候,会发现 pp.timers 字段是slice类型,其值类型是一个指针类型,这个切片变量(数组)会一直存在于整个应用程序的生命周期。如果不先赋值 nil 的话,GC 扫描的时候,会发现这些指针元素仍处于被切片引用状态,这样就导致一直占用内存(已无用的数据);如果先赋值的话,则在GC在扫描对象时,会发现指针元素已经没有任何对象在引用,就会立即被标记并清除(三色标记清除法),回收这些指针对象的内存。

总结

在了解这种用法前,很有必要了解当前应用的执行上下文及环境,如果只是一个临时变量且生命周期很短的话,就没有必要这样做了,如一个函数的栈变量。这里的环境P是长期处于运行状态中的指针变量,所以很有必要进行手动赋值为nil, 等待对象被GC回收。


本文来自:简书

感谢作者:路过100

查看原文:Golang中的切片与GC

相关阅读 >>

企业项目迁移Go-zero全攻略(二)

Golang 之 struct能不能比较

聊聊分析Golang的逃逸

手撸Golang Go与微服务 saga模式之4

手撸Golang Go与微服务 saga模式之3

Golang怎样读取json数据

手撸Golang 基本数据结构与算法 链表

Golang 如何类型转换

Golang 是什么写的

Golang 类似php中 http_build_query 方法

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...