zoukankan      html  css  js  c++  java
  • golang 内存池

    一般来说,内存池都是采用预分配的方式,分为固定大小的和非固定大小块,固定大小的内存效率高,非固定大小灵活。同时,分为单线程和多线程版的,单线程不需要考虑并发问题。 
    一般内存池的实现思想:分配一块比较大多内存,把这块内存分成大小相等的块,即固定大小,第一块要保存必要的信息,比如nfirst(第一块可分配到块),nsize(共分配了多少),nfree(可分配块大小),pnext(若是内存池不够,分配一块growth,pnext指向下一块),p(保存第一可分配内存块的地址),同时还需要poolmanage来统一做管理。每一个内存块的头两个字节记录下一个可分配的内存块的地址,因为是固定大小的,所以可以根据p和第几块算出地址。头两个字节分配的好处就是分配之后内存可复用,注意在归还到内存池的时候头两个字节也是需要记录下一个可分配的内存块地址。 
    这就是内存池的思想,好了,其实今天的主题不是内存池,而是另外一种内存管理的方法,按照块的大小来分配:

    type bys_i struct {
        E *list.Element
        T int64
    }
    
    type ByteSlice struct {
        P     *BytePool
        size_ int
        ls_   *list.List
        ls_m_ map[interface{}]*bys_i
        ls_l  sync.RWMutex
        zero_ *list.Element
    }
    type BytePool struct {
        // Max  int64
        T    int64 //timeout when gc
        Beg  int
        End  int
        ms_  map[int]*ByteSlice
        ms_l sync.RWMutex
    }

    按照块的大小来维护,比如map[8]*ByteSlice,map[1024]*ByteSlice,同时,用list来做垃圾回收处理,对每个元素都设置访问时间T,若是GC时,T(当前)-T(元素)>T(GC条件),从map中delete并从list中remove。这原理跟session很相似,都是用map来存储,用list来做垃圾回收,因为map读取速度快,而list插入等操作比较灵活。 
    go代码:

    func NewByteSlice(p *BytePool, size int) *ByteSlice {
        ls_ := list.New()
        zero_ := ls_.PushBack([]byte{})
        return &ByteSlice{
            P:     p,
            size_: size,
            ls_:   ls_,
            zero_: zero_,
            ls_m_: map[interface{}]*bys_i{},
        }
    }
    func (b *ByteSlice) Alloc() []byte {
        b.ls_l.Lock()
        defer b.ls_l.Unlock()
        var bys []byte
        tv := b.ls_.Front()
        if tv == b.zero_ {
            bys = make([]byte, b.size_)
            //add
            count++
            fmt.Printf("tv==b.zero_:%v,count:%d
    ", &bys[0], count)
            //end
            tv = b.ls_.PushBack(bys)
            b.ls_m_[&bys[0]] = &bys_i{
                E: tv,
                T: util.Now(),
            }
        } else {
            b.ls_.MoveToBack(tv)
            bys = tv.Value.([]byte)
            b.ls_m_[&bys[0]].T = util.Now()
            fmt.Printf("moveToBack:%v,%d,count:%d
    ", &bys[0], util.Now(), count)
        }
        return bys
    }
    func (b *ByteSlice) Free(bys []byte) {
        b.ls_l.Lock()
        defer b.ls_l.Unlock()
        if tv, ok := b.ls_m_[&bys[0]]; ok {
            tv.T = util.Now()
            b.ls_.MoveToFront(tv.E)
        }
    }
    func (b *ByteSlice) Size() int64 {
        // b.ls_l.Lock()
        // defer b.ls_l.Unlock()
        return int64(b.ls_.Len()-1) * int64(b.size_)
    }
    func (b *ByteSlice) GC() (int, int64) {
        b.ls_l.Lock()
        defer b.ls_l.Unlock()
        tn := util.Now()
        var rc int = 0
        for {
            tv := b.ls_.Front()
            if tv == b.zero_ {
                fmt.Printf("gc tv==b.zero_
    ")
                break
            }
            bys := tv.Value.([]byte)
            rv := &bys[0]
            if (tn - b.ls_m_[rv].T) > b.P.T {
                fmt.Printf("gc:%v
    ", rv)
                b.ls_.Remove(tv)
                delete(b.ls_m_, rv)
                rc++
            }
        }
        return rc, b.Size()
    } 


  • 相关阅读:
    zoj3888 找第二大
    zoj3882 博弈
    字典树小总结
    hdu2222 字典树
    hdu1247 字典树
    开放融合 | “引擎级”深度对接!POLARDB与SuperMap联合构建首个云原生时空平台
    阿里HBase高可用8年“抗战”回忆录
    最佳实践 | RDS & POLARDB归档到X-Pack Spark计算
    今日头条在消息服务平台和容灾体系建设方面的实践与思考
    饿了么监控系统 EMonitor 与美团点评 CAT 的对比
  • 原文地址:https://www.cnblogs.com/williamjie/p/9493073.html
Copyright © 2011-2022 走看看