返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

2.3.4 微小对象

发布于 2024-10-12 19:16:02 字数 2422 浏览 0 评论 0 收藏 0

微小对象(tiny)长度小于 16 字节,最常见的就是小字符串。

将多个微小对象组合起 来,用单 object 存储,可有效减少内存浪费。

// malloc.go

_TinySize      = 16
_TinySizeClass = int8(2)

maxTinySize   = _TinySize

按 tinySizeClass 取出一块 object,专用于微小对象分配。如果容量不足,则重新提取一块。

// mcache.go

type mcache struct {
    tiny             uintptr    // object ptr
    tinyoffset       uintptr
}

因垃圾回收缘故,用来组合的微小对象不能包含指针。直到存储单元里所有微小对象都不可达时,该内存才能回收。

通过偏移位置(tinyoffset)可判断剩余空间是否满足需求。如果可以,以此计算并返回内存地址。

不足,则提取新内存块,返回起始地址便可。最后,对比新旧两块内存,留下剩余空间更大的那块。

// malloc.go

// Allocate an object of size bytes.
// Small objects are allocated from the per-P cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.

func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
    
    if size <= maxSmallSize {
        if noscan && size < maxTinySize {
            
            // 微小对象 ...
            
            // 当前内存块(cache.tiny) 分配位置。
            off := c.tinyoffset
            
            // 对齐。
            if size&7 == 0 {
                off = alignUp(off, 8)
            } else if size&3 == 0 {
                off = alignUp(off, 4)
            } else if size&1 == 0 {
                off = alignUp(off, 2)
            }
            
            // 如果剩余空间足以分配,
            if off+size <= maxTinySize && c.tiny != 0 {
                // 计算内存地址,调整下次分配位置。
                x = unsafe.Pointer(c.tiny + off)
                c.tinyoffset = off + size
                return x
            }
            
            // 如果剩余空间不足,则从 cache ⾥新取一块 object。
            span = c.alloc[tinySpanClass]
            v := nextFreeFast(span)
            if v == 0 {
                v, span, shouldhelpgc = c.nextFree(tinySpanClass)
            }
            
            // 初始化新 object,返回起始地址即可。
            x = unsafe.Pointer(v)
            (*[2]uint64)(x)[0] = 0
            (*[2]uint64)(x)[1] = 0
            
            // 对⽐比新旧两块 tiny 内存,留留下剩余空间更大的那个。
            //    c.tiny == 0,表示 tiny object 不存在。
            //    因为 x 是新 object,那么 x.tinyoffset = size。
            //    对比新老 object.offset 就知道哪个剩余空间多。
            if size < c.tinyoffset || c.tiny == 0 {
                c.tiny = uintptr(x)
                c.tinyoffset = size
            }
        } else {
            ... 小对象 ...
        }
    } else {
        ... 大对象 ...
    }
    
    return x
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文