github.com/userpro/linearpool@v0.5.3-0.20231115092206-0ca073169b71/memorypool.go (about) 1 package memorypool 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 "unsafe" 8 ) 9 10 const ( 11 DiKB int64 = 1 << 10 12 DiMB int64 = DiKB << 10 13 DiGB int64 = DiMB << 10 14 defaultBlockSize int64 = DiKB * 4 // 4KB/block 15 ) 16 17 var ( 18 SliceExtendRatio = 2.5 19 BugfixClearPointerInMem = true 20 BugfixCorruptOtherMem = true 21 22 allocatorPool = sync.Pool{ 23 New: func() any { 24 return &Allocator{bidx: -1} 25 }, 26 } 27 ) 28 29 // Allocator 分配器 30 type Allocator struct { 31 blockSize int64 32 curBlock *sliceHeader 33 blocks []*sliceHeader 34 hugeBlocks []*sliceHeader 35 bidx int // 当前在第几个 block 进行分配 36 37 externalPtr []unsafe.Pointer 38 externalSlice []unsafe.Pointer 39 externalString []unsafe.Pointer 40 externalMap []any 41 externalFunc []any 42 43 subAlloctor []*Allocator // 子分配器 44 } 45 46 // NewAlloctorFromPool 新建分配池, blocksize >= bsize 47 func NewAlloctorFromPool(bsize int64) *Allocator { 48 ac := allocatorPool.Get().(*Allocator) 49 if bsize <= 0 { 50 bsize = defaultBlockSize 51 } 52 53 if ac.bidx < 0 { // 新建 alloctor 54 ac.blockSize = bsize 55 ac.newBlock() 56 } else if ac.blockSize < bsize { // 如果准备复用的 blocksize 小于所需要的, 则需要重新分配 57 ac.clearBlock() 58 ac.blockSize = bsize 59 ac.newBlock() 60 } 61 return ac 62 } 63 64 func (ac *Allocator) newBlockWithSz(need int64) *sliceHeader { 65 t := make([]byte, 0, need) 66 b := (*sliceHeader)(unsafe.Pointer(&t)) 67 ac.hugeBlocks = append(ac.hugeBlocks, b) 68 return b 69 } 70 71 func (ac *Allocator) newBlock() *sliceHeader { 72 ac.bidx++ 73 // 可能复用之前的blocks 74 if len(ac.blocks) > ac.bidx { 75 b := ac.blocks[ac.bidx] 76 ac.curBlock = b 77 return b 78 } 79 80 t := make([]byte, 0, ac.blockSize) 81 b := (*sliceHeader)(unsafe.Pointer(&t)) 82 ac.curBlock = b 83 ac.blocks = append(ac.blocks, b) 84 return b 85 } 86 87 func (ac *Allocator) clearBlock() { 88 ac.curBlock = nil 89 ac.blocks = nil 90 } 91 92 func (ac *Allocator) alloc(need int64) unsafe.Pointer { 93 if need == 0 && BugfixCorruptOtherMem { 94 return nil 95 } 96 97 // round up 98 needAligned := need 99 if need%ptrSize != 0 { 100 needAligned = (need + ptrSize + 1) & ^(ptrSize - 1) 101 } 102 103 // 分配小型对象 104 if ac.blockSize >= needAligned { 105 b := ac.curBlock 106 if b.Len+int64(needAligned) > b.Cap { 107 b = ac.newBlock() 108 } 109 110 ptr := unsafe.Add(b.Data, b.Len) 111 b.Len += needAligned 112 // fmt.Printf("bidx: %d, blocksize: %d, alloc need: %d, needAligned: %d, len: %d, %v - %v\n", 113 // ac.bidx, len(ac.blocks), need, needAligned, b.Len, ptr, unsafe.Add(b.Data, b.Cap-1)) 114 return ptr 115 } 116 117 // 分配巨型对象 118 b := ac.newBlockWithSz(needAligned) 119 ptr := b.Data 120 b.Len = b.Cap 121 // fmt.Printf("huge alloc need: %d, needAligned: %d, cap: %d, %v - %v\n", 122 // need, needAligned, b.Cap, b.Data, unsafe.Add(b.Data, b.Cap-1)) 123 return ptr 124 } 125 126 // Reset 重置内存信息 127 func (ac *Allocator) Reset() { 128 ac.bidx = 0 129 ac.curBlock = ac.blocks[0] 130 for _, b := range ac.blocks { 131 if b.Len > 0 { 132 memclrNoHeapPointers(b.Data, uintptr(b.Len)) 133 b.Len = 0 134 } 135 } 136 ac.blocks = ac.blocks[:1] 137 ac.hugeBlocks = nil // 大对象直接释放 避免过多占用内存 138 139 ac.externalPtr = ac.externalPtr[:0] 140 ac.externalSlice = ac.externalSlice[:0] 141 ac.externalString = ac.externalString[:0] 142 ac.externalMap = ac.externalMap[:0] 143 ac.externalFunc = ac.externalFunc[:0] 144 145 for i, subAc := range ac.subAlloctor { 146 subAc.Reset() 147 ac.subAlloctor[i] = nil 148 } 149 ac.subAlloctor = ac.subAlloctor[:0] 150 } 151 152 // ReturnAlloctorToPool 归还分配池 153 func (ac *Allocator) ReturnAlloctorToPool() { 154 ac.Reset() 155 allocatorPool.Put(ac) 156 } 157 158 // BlockSize 获取当前内存池的 blocksize 159 func (ac *Allocator) BlockSize() int64 { 160 return ac.blockSize 161 } 162 163 // AddSubAlloctor 新增子分配器 164 func (ac *Allocator) AddSubAlloctor(sub *Allocator) { 165 ac.subAlloctor = append(ac.subAlloctor, sub) 166 } 167 168 // SubAlloctor 获取子分配器 169 func (ac *Allocator) SubAlloctor() []*Allocator { 170 return ac.subAlloctor 171 } 172 173 // Merge 合并其他内存池 174 func (ac *Allocator) Merge(src *Allocator) *Allocator { 175 ac.blocks = append(ac.blocks, src.blocks[:src.bidx+1]...) 176 ac.hugeBlocks = append(ac.hugeBlocks, src.hugeBlocks...) 177 ac.bidx = ac.bidx + src.bidx + 1 178 179 ac.externalPtr = append(ac.externalPtr, src.externalPtr...) 180 ac.externalSlice = append(ac.externalSlice, src.externalSlice...) 181 ac.externalString = append(ac.externalString, src.externalString...) 182 ac.externalMap = append(ac.externalMap, src.externalMap...) 183 ac.externalFunc = append(ac.externalFunc, src.externalFunc...) 184 return ac 185 } 186 187 // KeepAlive GC保活 188 func (ac *Allocator) KeepAlive(ptr interface{}) { 189 d := data(ptr) 190 if d == nil { 191 return 192 } 193 194 k := reflect.TypeOf(ptr).Kind() 195 switch k { 196 case reflect.Ptr: 197 ac.externalPtr = append(ac.externalPtr, d) 198 case reflect.Slice: 199 ac.externalSlice = append(ac.externalSlice, (*sliceHeader)(d).Data) 200 case reflect.String: 201 ac.externalString = append(ac.externalString, (*stringHeader)(d).Data) 202 case reflect.Map: 203 ac.externalMap = append(ac.externalMap, d) 204 case reflect.Func: 205 ac.externalFunc = append(ac.externalFunc, ptr) 206 default: 207 panic(fmt.Errorf("unsupported type: %v", k)) 208 } 209 } 210 211 // New 分配新对象 212 func New[T any](ac *Allocator) (r *T) { 213 r = (*T)(ac.alloc(int64(unsafe.Sizeof(*r)))) 214 return r 215 } 216 217 // NewSlice does not zero the slice automatically, this is OK with most cases and can improve the performance. 218 // zero it yourself for your need. 219 func NewSlice[T any](ac *Allocator, len, cap int) (r []T) { 220 // keep same with systems `new`. 221 if len > cap { 222 panic("NewSlice: cap out of range") 223 } 224 225 if BugfixCorruptOtherMem && cap == 0 { 226 } 227 228 slice := (*sliceHeader)(unsafe.Pointer(&r)) 229 var t T 230 slice.Data = ac.alloc(int64(cap) * int64(unsafe.Sizeof(t))) 231 slice.Len = int64(len) 232 slice.Cap = int64(cap) 233 return r 234 } 235 236 // AppendMulti append slice 237 func AppendMulti[T any](ac *Allocator, s []T, elems ...T) []T { 238 if len(elems) == 0 { 239 return s 240 } 241 242 h := (*sliceHeader)(unsafe.Pointer(&s)) 243 elemSz := int(unsafe.Sizeof(elems[0])) 244 src := (*sliceHeader)(unsafe.Pointer(&elems)) 245 246 // grow 247 if h.Len+src.Len > h.Cap { 248 pre := *h 249 h.Cap = int64(roundupsize(uintptr(pre.Cap + int64(len(elems))))) 250 sz := int(h.Cap) * elemSz 251 h.Data = ac.alloc(int64(sz)) 252 memmoveNoHeapPointers(h.Data, pre.Data, uintptr(int(pre.Len)*elemSz)) 253 } 254 255 // append 256 memmoveNoHeapPointers(unsafe.Add(h.Data, elemSz*int(h.Len)), src.Data, uintptr(elemSz*int(src.Len))) 257 h.Len += src.Len 258 259 return s 260 } 261 262 // Append append slice 263 func Append[T any](ac *Allocator, s []T, elem T) []T { 264 h := (*sliceHeader)(unsafe.Pointer(&s)) 265 elemSz := int(unsafe.Sizeof(elem)) 266 267 // grow 268 if h.Len+1 > h.Cap { 269 pre := *h 270 h.Cap = int64(roundupsize(uintptr(pre.Cap + 1))) 271 sz := int(h.Cap) * elemSz 272 h.Data = ac.alloc(int64(sz)) 273 memmoveNoHeapPointers(h.Data, pre.Data, uintptr(int(pre.Len)*elemSz)) 274 } 275 276 // append 277 *(*T)(unsafe.Add(h.Data, elemSz*int(h.Len))) = elem 278 h.Len += 1 279 280 return s 281 } 282 283 // AppendInplaceMulti 与 NewSlice 之间没有任何新的内存分配时使用 284 func AppendInplaceMulti[T any](ac *Allocator, s []T, elems ...T) []T { 285 if len(elems) == 0 { 286 return s 287 } 288 289 h := (*sliceHeader)(unsafe.Pointer(&s)) 290 elemSz := int(unsafe.Sizeof(elems[0])) 291 src := (*sliceHeader)(unsafe.Pointer(&elems)) 292 293 // grow 294 if h.Len+src.Len > h.Cap { 295 pre := *h 296 newcap := int64(roundupsize(uintptr(pre.Cap + int64(len(elems))))) 297 curB := ac.curBlock 298 growthInplace := (newcap - pre.Cap) * int64(elemSz) 299 if curB.Len+growthInplace < curB.Cap { 300 curB.Len += growthInplace 301 } else { 302 sz := int(newcap) * elemSz 303 h.Data = ac.alloc(int64(sz)) 304 memmoveNoHeapPointers(h.Data, pre.Data, uintptr(int(pre.Len)*elemSz)) 305 } 306 h.Cap = newcap 307 } 308 309 // append 310 memmoveNoHeapPointers(unsafe.Add(h.Data, elemSz*int(h.Len)), src.Data, uintptr(elemSz*int(src.Len))) 311 h.Len += src.Len 312 313 return s 314 } 315 316 // AppendInplace 与 NewSlice 之间没有任何新的内存分配时使用 317 func AppendInplace[T any](ac *Allocator, s []T, elem T) []T { 318 h := (*sliceHeader)(unsafe.Pointer(&s)) 319 elemSz := int(unsafe.Sizeof(elem)) 320 321 // grow 322 if h.Len+1 > h.Cap { 323 pre := *h 324 newcap := int64(roundupsize(uintptr(pre.Cap + 1))) 325 if ac.curBlock.Len+newcap-h.Cap < ac.curBlock.Cap { 326 ac.curBlock.Len += newcap - h.Cap 327 } else { 328 sz := int(newcap) * elemSz 329 h.Data = ac.alloc(int64(sz)) 330 memmoveNoHeapPointers(h.Data, pre.Data, uintptr(int(pre.Len)*elemSz)) 331 } 332 h.Cap = newcap 333 } 334 335 // append 336 *(*T)(unsafe.Add(h.Data, elemSz*int(h.Len))) = elem 337 h.Len += 1 338 339 return s 340 } 341 342 // AppendInbound 确定范围内 append 343 func AppendInbound[T any](ac *Allocator, s []T, elem T) []T { 344 if len(s)+1 > cap(s) { 345 panic(fmt.Sprintf("index %d out of bound cap %d", len(s), cap(s))) 346 } 347 348 return append(s, elem) 349 } 350 351 // NewString 从内存池分配 string 352 func (ac *Allocator) NewString(v string) string { 353 if len(v) == 0 { 354 return "" 355 } 356 h := (*stringHeader)(unsafe.Pointer(&v)) 357 ptr := ac.alloc(int64(h.Len)) 358 if ptr != nil { 359 memmoveNoHeapPointers(ptr, h.Data, uintptr(h.Len)) 360 } 361 h.Data = ptr 362 return v 363 } 364 365 // Debug 输出 debug 信息 366 func (ac *Allocator) Debug() { 367 fmt.Printf("\n* bidx: %d\n", ac.bidx) 368 fmt.Printf("* blocks: \n") 369 fmt.Printf(" - curblock: len(%d) cap(%d) addr[%p - %p]\n", ac.curBlock.Len, ac.curBlock.Cap, ac.curBlock.Data, unsafe.Add(ac.curBlock.Data, ac.curBlock.Cap-1)) 370 for i, b := range ac.blocks { 371 b1 := *(*[]byte)(unsafe.Pointer(b)) 372 fmt.Printf(" - b[%d]: len(%d) cap(%d) addr[%p - %p] data: %v\n", i, b.Len, b.Cap, b.Data, unsafe.Add(b.Data, b.Cap-1), b1) 373 } 374 375 if len(ac.hugeBlocks) > 0 { 376 fmt.Printf("* huge blocks: \n") 377 for i, b := range ac.hugeBlocks { 378 b1 := *(*[]byte)(unsafe.Pointer(b)) 379 fmt.Printf(" - hb[%d]: len(%d) cap(%d) addr[%p - %p] data: %v\n", i, b.Len, b.Cap, b.Data, unsafe.Add(b.Data, b.Cap-1), b1) 380 } 381 } 382 fmt.Printf("\n") 383 } 384 385 //============================================================================ 386 // Protobuf2 APIs 387 //============================================================================ 388 389 // Bool ... 390 func (ac *Allocator) Bool(v bool) (r *bool) { 391 r = (*bool)(ac.alloc(int64(unsafe.Sizeof(v)))) 392 *r = v 393 return 394 } 395 396 // Int ... 397 func (ac *Allocator) Int(v int) (r *int) { 398 r = (*int)(ac.alloc(int64(unsafe.Sizeof(v)))) 399 *r = v 400 return 401 } 402 403 // Int32 ... 404 func (ac *Allocator) Int32(v int32) (r *int32) { 405 r = (*int32)(ac.alloc(int64(unsafe.Sizeof(v)))) 406 *r = v 407 return 408 } 409 410 // Uint32 ... 411 func (ac *Allocator) Uint32(v uint32) (r *uint32) { 412 r = (*uint32)(ac.alloc(int64(unsafe.Sizeof(v)))) 413 *r = v 414 return 415 } 416 417 // Int64 ... 418 func (ac *Allocator) Int64(v int64) (r *int64) { 419 r = (*int64)(ac.alloc(int64(unsafe.Sizeof(v)))) 420 *r = v 421 return 422 } 423 424 // Uint64 ... 425 func (ac *Allocator) Uint64(v uint64) (r *uint64) { 426 r = (*uint64)(ac.alloc(int64(unsafe.Sizeof(v)))) 427 *r = v 428 return 429 } 430 431 // Float32 ... 432 func (ac *Allocator) Float32(v float32) (r *float32) { 433 r = (*float32)(ac.alloc(int64(unsafe.Sizeof(v)))) 434 *r = v 435 return 436 } 437 438 // Float64 ... 439 func (ac *Allocator) Float64(v float64) (r *float64) { 440 r = (*float64)(ac.alloc(int64(unsafe.Sizeof(v)))) 441 *r = v 442 return 443 } 444 445 // String ... 446 func (ac *Allocator) String(v string) (r *string) { 447 r = (*string)(ac.alloc(int64(unsafe.Sizeof(v)))) 448 *r = ac.NewString(v) 449 return 450 }