linearAlloc问题

最近重新看go源码(1.12版本),对于这块代码有个疑问,为什么增加映射保留空间,l.end不用变化

func (l *linearAlloc) alloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
    p := round(l.next, align)
    if p+size > l.end {
        return nil
    }
    l.next = p + size
    if pEnd := round(l.next-1, physPageSize); pEnd > l.mapped {
        // We need to map more of the reserved space.
        sysMap(unsafe.Pointer(l.mapped), pEnd-l.mapped, sysStat)
        l.mapped = pEnd
    }
    return unsafe.Pointer(p)
}
已邀请:

jk201310

赞同来自:

没人回答,自己给自己一个答案吧,

  • 首先,这块代码只会在32位机器上使用
  • 其次,这块代码是在预分配的空间上分配内存,
        p := firstmoduledata.end
        if p < procBrk {
            p = procBrk
        }
        if mheap_.heapArenaAlloc.next <= p && p < mheap_.heapArenaAlloc.end {
            p = mheap_.heapArenaAlloc.end
        }
        p = round(p+(256<<10), heapArenaBytes)
        // Because we're worried about fragmentation on
        // 32-bit, we try to make a large initial reservation.
        arenaSizes := []uintptr{
            512 << 20,
            256 << 20,
            128 << 20,
        }
        for _, arenaSize := range arenaSizes {
            a, size := sysReserveAligned(unsafe.Pointer(p), arenaSize, heapArenaBytes)
            if a != nil {
                mheap_.arena.init(uintptr(a), size)
                p = uintptr(a) + size // For hint below
                break
            }
        }
        hint := (*arenaHint)(mheap_.arenaHintAlloc.alloc())
        hint.addr = p
        hint.next, mheap_.arenaHints = mheap_.arenaHints, hint
  • 最后,关系到sysReserveAligned和sysMap函数作用上的不同

jk201310

赞同来自:

  • sysReserveAligned 最终的实现是
    func sysReserve(v unsafe.Pointer, n uintptr) unsafe.Pointer {
    p, err := mmap(v, n, _PROT_NONE, _MAP_ANONYMOUS|_MAP_PRIVATE, -1, 0)
    if err != 0 {
        return nil
    }
    return p
    }

    可以看到,只是匿名映射一块空间,没有加读写权限,

  • sysMap

    func sysMap(v unsafe.Pointer, n uintptr, sysStat *uint64) {
    mSysStatInc(sysStat, n)
    
    // AIX does not allow mapping a range that is already mapped.
    // So always unmap first even if it is already unmapped.
    munmap(v, n)
    p, err := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANONYMOUS|_MAP_FIXED|_MAP_PRIVATE, -1, 0)
    
    if err == _ENOMEM {
        throw("runtime: out of memory")
    }
    if p != v || err != 0 {
        throw("runtime: cannot map pages in arena address space")
    }
    }

    这个函数会对这块空间加上读写权限,这就是为什么继续映射内核空间而end不增加的原因

要回复问题请先登录注册