github.com/sandwich-go/boost@v1.3.29/xpool/buffer.go (about)

     1  package xpool
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  )
     7  
     8  // BytesPool bytes pool
     9  type BytesPool interface {
    10  	// Alloc try alloc a []byte from internal slab class if no free chunk in slab class Alloc will make one.
    11  	Alloc(size int) []byte
    12  	// Free release a []byte that alloc from BytesPool.Alloc.
    13  	Free(mem []byte)
    14  }
    15  
    16  var debug bool
    17  
    18  // SyncBytesPool is a sync.Pool base slab allocation memory pool
    19  type SyncBytesPool struct {
    20  	chunks  []sync.Pool
    21  	sizes   []int
    22  	minSize int
    23  	maxSize int
    24  
    25  	// for testing
    26  	allocTimesFromPool int
    27  	freeTimesToPool    int
    28  }
    29  
    30  // NewSyncBytesPool create a sync.Pool base slab allocation memory pool.
    31  // minSize is the smallest chunk size.
    32  // maxSize is the largest chunk size.
    33  // factor is used to control growth of chunk size.
    34  func NewSyncBytesPool(minSize, maxSize, factor int) BytesPool {
    35  	n := 0
    36  	if minSize <= 0 || factor <= 0 {
    37  		panic(fmt.Sprintf("invalid paramter, minSize/factor should greater than 0"))
    38  	}
    39  	for chunkSize := minSize; chunkSize <= maxSize; chunkSize *= factor {
    40  		n++
    41  	}
    42  	pool := &SyncBytesPool{
    43  		chunks:  make([]sync.Pool, n),
    44  		sizes:   make([]int, n),
    45  		minSize: minSize, maxSize: maxSize,
    46  	}
    47  	n = 0
    48  	for chunkSize := minSize; chunkSize <= maxSize; chunkSize *= factor {
    49  		pool.sizes[n] = chunkSize
    50  		pool.chunks[n].New = func(size int) func() interface{} {
    51  			return func() interface{} {
    52  				buf := make([]byte, size)
    53  				return &buf
    54  			}
    55  		}(chunkSize)
    56  		n++
    57  	}
    58  	return pool
    59  }
    60  
    61  // Alloc try alloc a []byte from internal slab class if no free chunk in slab class Alloc will make one.
    62  func (p *SyncBytesPool) Alloc(size int) []byte {
    63  	if size <= p.maxSize {
    64  		for i := 0; i < len(p.sizes); i++ {
    65  			if p.sizes[i] >= size {
    66  				mem := p.chunks[i].Get().(*[]byte)
    67  				if debug {
    68  					p.allocTimesFromPool++
    69  				}
    70  				return (*mem)[:size]
    71  			}
    72  		}
    73  	}
    74  	return make([]byte, size)
    75  }
    76  
    77  // Free release a []byte that alloc from SyncBytesPool.Alloc.
    78  func (p *SyncBytesPool) Free(mem []byte) {
    79  	if size := cap(mem); size <= p.maxSize {
    80  		for i := 0; i < len(p.sizes); i++ {
    81  			if p.sizes[i] == size {
    82  				p.chunks[i].Put(&mem)
    83  				if debug {
    84  					p.freeTimesToPool++
    85  				}
    86  				return
    87  			} else if p.sizes[i] > size && i > 0 && p.sizes[i-1] <= size {
    88  				p.chunks[i-1].Put(&mem)
    89  				if debug {
    90  					p.freeTimesToPool++
    91  				}
    92  				return
    93  			}
    94  		}
    95  	}
    96  }