業務中有這樣一個struct:
type bizData struct{
A uint64
B uint64
C int32
D uint32
}
雖然沒有實測,但我猜測這樣的對齊方式,這個struct占24字節。
業務中用一個map指向這些對象: map[uint64]*bizData
這樣的存儲對象,一個容器開啟10GB內存,最多存儲60萬左右的對象,容器內存就爆了。
於是自己實現一個簡易的內存池:mempool.go
package mempool
//實現一個按塊擴展的內存池
type memPool struct {
datas [][]bizData
freeNode chan uint32
countOfBlock int
}
//NewMemPool 構造內存池對象
func NewMemPool(countOfBlock int) *memPool {
out := &memPool{
datas: [][]bizData{make([]bizData, countOfBlock)},
freeNode: make(chan uint32, countOfBlock),
countOfBlock: countOfBlock,
}
for i := 0; i < countOfBlock; i++ {
out.freeNode <- uint32(i)
}
return out
}
func (pool *memPool) moreBlock() {
pool.datas = append(pool.datas, make([]bizData, pool.countOfBlock))
ch := make(chan uint32, len(pool.datas)*pool.countOfBlock)
close(pool.freeNode)
for item := range pool.freeNode {
ch <- item
}
start := (len(pool.datas) - 1) * pool.countOfBlock
for i := 0; i < pool.countOfBlock; i++ {
ch <- uint32(start + i)
}
pool.freeNode = ch
}
func (pool *memPool) Get() uint32 {
if len(pool.freeNode) == 0 {
pool.moreBlock()
}
select {
case idx := <-pool.freeNode:
return idx
default:
panic("impossible")
}
}
func (pool *memPool) Put(idx uint32) {
pool.freeNode <- idx
}
func (pool *memPool) Item(idx uint32) *bizData {
blockIdx := int(idx) / pool.countOfBlock
loc := int(idx) % pool.countOfBlock
return &(pool.datas[blockIdx][loc])
}
然后把對象的引用方式修改為: map[uint64]uint32 //值映射數據塊的下標
使用上面的內存池后,分配250萬小對象,進程內存始終未超過600mb!!
so, 大量小對象的情況下,自己實現內存池更好!