博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang 内存池
阅读量:5112 次
发布时间:2019-06-13

本文共 2355 字,大约阅读时间需要 7 分钟。

一般来说,内存池都是采用预分配的方式,分为固定大小的和非固定大小块,固定大小的内存效率高,非固定大小灵活。同时,分为单线程和多线程版的,单线程不需要考虑并发问题。 

一般内存池的实现思想:分配一块比较大多内存,把这块内存分成大小相等的块,即固定大小,第一块要保存必要的信息,比如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() } 

转载于:https://www.cnblogs.com/williamjie/p/9493073.html

你可能感兴趣的文章
《Linux命令行与shell脚本编程大全》 第六章环境变量
查看>>
Java集合框架学习总结
查看>>
commands 模块 与sys模块
查看>>
洛谷 P2234 [HNOI2002]营业额统计
查看>>
SetTimeOut 与 SetInterval 区别
查看>>
VC++编程 两类典型的 LNK2001错误分析及解决方法
查看>>
对于redis框架的理解(三)
查看>>
C语言模块化编译介绍
查看>>
file控件,以及fileList对象。
查看>>
关于多线程(GCD介绍)
查看>>
设计模式之观察者模式
查看>>
T-SQL基础(五)之增删改
查看>>
Jzoj4786 小a的强迫症
查看>>
redis配置密码
查看>>
bootstrap之辅助类
查看>>
子元素定位,父元素高度自适应
查看>>
js获取json属性值的两种方法
查看>>
[Algorithms] Queue & Priority Queue
查看>>
[React + Functional Programming ADT] Connect State ADT Based Redux Actions to a React Application
查看>>
[RxJS] Getting Input Text with Map
查看>>