一般來說,記憶體池都是採用預分配的方式,分為固定大小的和非固定大小塊,固定大小的記憶體效率高,非固定大小靈活。同時,分為單線程和多線程版的,單線程不需要考慮並發問題。
一般記憶體池的實現思想:分配一塊比較大多記憶體,把這塊記憶體分成大小相等的塊,即固定大小,第一塊要儲存必要的資訊,比如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\n", &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\n", &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_\n") break } bys := tv.Value.([]byte) rv := &bys[0] if (tn - b.ls_m_[rv].T) > b.P.T { fmt.Printf("gc:%v\n", rv) b.ls_.Remove(tv) delete(b.ls_m_, rv) rc++ } } return rc, b.Size()}