mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-28 02:50:25 +08:00
优化计数器内存使用
This commit is contained in:
@@ -3,14 +3,16 @@
|
|||||||
package counters
|
package counters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
|
||||||
syncutils "github.com/TeaOSLab/EdgeNode/internal/utils/sync"
|
syncutils "github.com/TeaOSLab/EdgeNode/internal/utils/sync"
|
||||||
"github.com/cespare/xxhash"
|
"github.com/cespare/xxhash"
|
||||||
"runtime"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const maxItemsPerGroup = 100_000
|
||||||
|
|
||||||
type Counter struct {
|
type Counter struct {
|
||||||
countMaps uint64
|
countMaps uint64
|
||||||
locker *syncutils.RWMutex
|
locker *syncutils.RWMutex
|
||||||
@@ -23,7 +25,7 @@ type Counter struct {
|
|||||||
|
|
||||||
// NewCounter create new counter
|
// NewCounter create new counter
|
||||||
func NewCounter() *Counter {
|
func NewCounter() *Counter {
|
||||||
var count = runtime.NumCPU() * 4
|
var count = utils.SystemMemoryGB() * 2
|
||||||
if count < 8 {
|
if count < 8 {
|
||||||
count = 8
|
count = 8
|
||||||
} else if count > 128 {
|
} else if count > 128 {
|
||||||
@@ -162,15 +164,36 @@ func (this *Counter) GC() {
|
|||||||
expiredKeys = append(expiredKeys, key)
|
expiredKeys = append(expiredKeys, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var tooManyItems = len(itemMap) > maxItemsPerGroup // prevent too many items
|
||||||
this.locker.RUnlock(gcIndex)
|
this.locker.RUnlock(gcIndex)
|
||||||
|
|
||||||
if len(expiredKeys) > 0 {
|
if len(expiredKeys) > 0 {
|
||||||
for _, key := range expiredKeys {
|
|
||||||
this.locker.Lock(gcIndex)
|
this.locker.Lock(gcIndex)
|
||||||
|
for _, key := range expiredKeys {
|
||||||
delete(itemMap, key)
|
delete(itemMap, key)
|
||||||
|
}
|
||||||
this.locker.Unlock(gcIndex)
|
this.locker.Unlock(gcIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tooManyItems {
|
||||||
|
this.locker.Lock(gcIndex)
|
||||||
|
var count = len(itemMap) - maxItemsPerGroup
|
||||||
|
if count > 0 {
|
||||||
|
itemMap = this.itemMaps[gcIndex]
|
||||||
|
for key := range itemMap {
|
||||||
|
delete(itemMap, key)
|
||||||
|
count--
|
||||||
|
if count < 0 {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.locker.Unlock(gcIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *Counter) CountMaps() int {
|
||||||
|
return int(this.countMaps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate hash of the key
|
// calculate hash of the key
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/iwind/TeaGo/types"
|
"github.com/iwind/TeaGo/types"
|
||||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"runtime/debug"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -78,14 +79,20 @@ func TestCounterMemory(t *testing.T) {
|
|||||||
var stat = &runtime.MemStats{}
|
var stat = &runtime.MemStats{}
|
||||||
runtime.ReadMemStats(stat)
|
runtime.ReadMemStats(stat)
|
||||||
|
|
||||||
var counter = counters.NewCounter()
|
var counter = counters.NewCounter().WithGC()
|
||||||
for i := 0; i < 1e5; i++ {
|
for i := 0; i < 1_000_000; i++ {
|
||||||
counter.Increase(uint64(i), rands.Int(10, 300))
|
counter.Increase(uint64(i), rands.Int(10, 300))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runtime.GC()
|
||||||
|
runtime.GC()
|
||||||
|
debug.FreeOSMemory()
|
||||||
|
|
||||||
var stat1 = &runtime.MemStats{}
|
var stat1 = &runtime.MemStats{}
|
||||||
runtime.ReadMemStats(stat1)
|
runtime.ReadMemStats(stat1)
|
||||||
t.Log((stat1.TotalAlloc-stat.TotalAlloc)/(1<<20), "MB")
|
t.Log((stat1.TotalAlloc-stat.TotalAlloc)/(1<<20), "MB")
|
||||||
|
|
||||||
|
t.Log(counter.TotalItems())
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCounter_Increase(b *testing.B) {
|
func BenchmarkCounter_Increase(b *testing.B) {
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ func NewItem(lifeSeconds int) *Item {
|
|||||||
spanSeconds = 1
|
spanSeconds = 1
|
||||||
}
|
}
|
||||||
var countSpans = lifeSeconds/spanSeconds + 1 /** prevent index out of bounds **/
|
var countSpans = lifeSeconds/spanSeconds + 1 /** prevent index out of bounds **/
|
||||||
var spans = []*Span{}
|
var spans = make([]*Span, countSpans)
|
||||||
for i := 0; i < countSpans; i++ {
|
for i := 0; i < countSpans; i++ {
|
||||||
spans = append(spans, NewSpan())
|
spans[i] = NewSpan()
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Item{
|
return &Item{
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
package counters
|
package counters
|
||||||
|
|
||||||
type Span struct {
|
type Span struct {
|
||||||
Timestamp int64
|
|
||||||
Count uint64
|
Count uint64
|
||||||
|
Timestamp int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSpan() *Span {
|
func NewSpan() *Span {
|
||||||
|
|||||||
Reference in New Issue
Block a user