核心API实现

mallocinit()

func mallocinit() {

    initSizes()

    ...

    // linux下最终调用mmap()来预留虚拟内存空间
    // 预留的大小为_MaxMem,在linux amd_64为512GB
    if ptrSize == 8 && (limit == 0 || limit > 1<<30) {
        // 计算各部分占用的空间,总空间为各项之和
        arenaSize := round(_MaxMem, _PageSize)
        bitmapSize = arenaSize / (ptrSize * 8 / 4)
        spansSize = arenaSize / _PageSize * ptrSize
        spansSize = round(spansSize, _PageSize)

        // 尝试从0xc000000000开始设置保留地址
        // 失败,则尝试0x1c000000000~0x7fc000000000
        for i := 0; i <= 0x7f; i++ {
            switch {
            case GOARCH == "arm64" && GOOS == "darwin":
                p = uintptr(i)<<40 | uintptrMask&(0x0013<<28)
            case GOARCH == "arm64":
                p = uintptr(i)<<40 | uintptrMask&(0x0040<<32)
            default:
                p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
            }
            // 之所以多分配一个_PageSize是因为mmap()分配出的可能不是按照_PageSize对其的,如果这样我们需要进行再对其
            pSize = bitmapSize + spansSize + arenaSize + _PageSize
            p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
            if p != 0 {
                break
            }
        }
        if p == 0 {
                ......
        }
    }
    // 按_PageSize对其,也是前面多分配一个_PageSize的原因
    p1 := round(p, _PageSize)

    // 初始化heap管理的各字段
    mheap_.spans = (**mspan)(unsafe.Pointer(p1))
    mheap_.bitmap = p1 + spansSize
    mheap_.arena_start = p1 + (spansSize + bitmapSize)
    mheap_.arena_used = mheap_.arena_start
    mheap_.arena_end = p + pSize
    mheap_.arena_reserved = reserved

    if mheap_.arena_start&(_PageSize-1) != 0 {
        ......
    }
    // 初始化全局heap
    mHeap_Init(&mheap_, spansSize)
    _g_ := getg()

    // 为当前线程绑定cache对象
    _g_.m.mcache = allocmcache()
}

内存管理初始化在go进程被启动时调用,负责向os申请预留虚拟内存空间,并将该虚拟空间分为以下几个部分:

页所属span指针数组 || GC标记位图 || 用户内存分配区域
+---------------------+---------------+-----------------------------+
| spans 512MB .......| bitmap 32GB | arena 512GB ..................|
+---------------------+---------------+-----------------------------+

spans 512MB: ???
bitmap 32GB: ???
arena 512GB: ???

mallocgc()

// implementation of new builtin
func newobject(typ *_type) unsafe.Pointer {
    flags := uint32(0)
    if typ.kind&kindNoPointers != 0 {
        flags |= flagNoScan
    }
    return mallocgc(uintptr(typ.size), typ, flags)
}

// 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, flags uint32) unsafe.Pointer {
    // Set mp.mallocing to keep from being preempted by GC.
    mp := acquirem()
    if mp.mallocing != 0 {
        throw("malloc deadlock")
    }
    if mp.gsignal == getg() {
        throw("malloc during signal")
    }
    mp.mallocing = 1

    shouldhelpgc := false
    dataSize := size
    c := gomcache()
    var s *mspan
    var x unsafe.Pointer

    // 小对象(<32KB)分配
    if size <= maxSmallSize {
        // 对极小对象(<=16B)分配的优化,见“性能优化”
        if flags&flagNoScan != 0 && size < maxTinySize {
            ......
        } else {
            var sizeclass int8
            if size <= 1024-8 {
                sizeclass = size_to_class8[(size+7)>>3]
            } else {
                sizeclass = size_to_class128[(size-1024+127)>>7]
            }
            size = uintptr(class_to_size[sizeclass])
            // 从线程本地cache的freelist分配
            s = c.alloc[sizeclass]
            v := s.freelist
            // 如果线程本地cache的freelist为空
            // 首先从全局heap中为本地线程分配一批
            if v.ptr() == nil {
                systemstack(func() {
                    mCache_Refill(c, int32(sizeclass))
                })
                shouldhelpgc = true
                s = c.alloc[sizeclass]
                v = s.freelist
            }
            s.freelist = v.ptr().next
            s.ref++
            // ?
            prefetchnta(uintptr(v.ptr().next))
            x = unsafe.Pointer(v)
            if flags&flagNoZero == 0 {
                v.ptr().next = 0
                if size > 2*ptrSize && ((*[2]uintptr)(x))[1] != 0 {
                    memclr(unsafe.Pointer(v), size)
                }
            }
        }
        c.local_cachealloc += size
    // 对大对象(>32KB)的分配    
    } else {
        var s *mspan
        shouldhelpgc = true
        systemstack(func() {
            s = largeAlloc(size, uint32(flags))
        })
        x = unsafe.Pointer(uintptr(s.start << pageShift))
        size = uintptr(s.elemsize)
    }
    ......
    return x
}

results matching ""

    No results matching ""