You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
go map has a memory leak,can help fix it?
I now use two go map to fix it, if not use this way to avoid the memory leak problem
the reason is that go map delete a key only to label it ,but not really delete it, so the memory can increase always. Using the two map way sets the go map to nil that solves the problem.
func (bmap *BetterMap) DelKey(key interface{}) {
if bmap.useMapIndex == 1 {
delete(bmap.firstMap, key)
bmap.totalDeleteNum++
if bmap.totalDeleteNum >= bmap.deleteNumThresh {
bmap.secondMap = make(map[interface{}]interface{}, len(bmap.firstMap))
for i, v := range bmap.firstMap {
bmap.secondMap[i] = v
}
bmap.useMapIndex = 2
bmap.totalDeleteNum = 0
bmap.firstMap = nil
}
} else {
delete(bmap.secondMap, key)
bmap.totalDeleteNum++
if bmap.totalDeleteNum >= bmap.deleteNumThresh {
bmap.firstMap = make(map[interface{}]interface{}, len(bmap.secondMap))
for i, v := range bmap.secondMap {
bmap.firstMap[i] = v
}
bmap.useMapIndex = 1
bmap.totalDeleteNum = 0
bmap.secondMap = nil
}
}
}package simplelru
import (
"container/list"
"errors"
)
// EvictCallback is used to get a callback when a cache entry is evicted
type EvictCallback func(key interface{}, value interface{})
// LRU implements a non-thread safe fixed size LRU cache
type LRU struct {
size int
evictList *list.List
//items map[interface{}]*list.Element
betterMap *BetterMap
onEvict EvictCallback
}
// entry is used to hold a value in the evictList
type entry struct {
key interface{}
value interface{}
}
// NewLRU constructs an LRU of the given size
func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
if size <= 0 {
return nil, errors.New("Must provide a positive size")
}
c := &LRU{
size: size,
evictList: list.New(),
betterMap: NewBetterMap(int32(size)),
onEvict: onEvict,
}
return c, nil
}
// Purge is used to completely clear the cache.
func (c *LRU) Purge() {
c.betterMap.Purge()
c.betterMap = NewBetterMap(int32(c.size))
c.evictList.Init()
}
// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *LRU) Add(key, value interface{}) (evicted bool) {
// Check for existing item
if ent, ok := c.betterMap.GetValue(key); ok {
c.evictList.MoveToFront(ent.(*list.Element))
ent.(*list.Element).Value.(*entry).value = value
return false
}
// Add new item
ent := &entry{key, value}
entry := c.evictList.PushFront(ent)
//c.items[key] = entry
c.betterMap.Set(key, entry)
evict := c.evictList.Len() > c.size
// Verify size not exceeded
if evict {
c.removeOldest()
}
return evict
}
// Get looks up a key's value from the cache.
func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
if ent, ok := c.betterMap.GetValue(key); ok {
c.evictList.MoveToFront(ent.(*list.Element))
return ent.(*list.Element).Value.(*entry).value, true
}
return
}
// Contains checks if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
func (c *LRU) Contains(key interface{}) (ok bool) {
_, ok = c.betterMap.GetValue(key)
return ok
}
// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
if ent, ok := c.betterMap.GetValue(key); ok {
return ent.(*list.Element).Value.(*entry).value, true
}
return nil, ok
}
// Remove removes the provided key from the cache, returning if the
// key was contained.
func (c *LRU) Remove(key interface{}) (present bool) {
if ent, ok := c.betterMap.GetValue(key); ok {
c.removeElement(ent.(*list.Element))
return true
}
return false
}
// RemoveOldest removes the oldest item from the cache.
func (c *LRU) RemoveOldest() (key, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent)
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return nil, nil, false
}
// GetOldest returns the oldest entry
func (c *LRU) GetOldest() (key, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return nil, nil, false
}
// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *LRU) Keys() []interface{} {
keys := make([]interface{}, c.betterMap.GetLen())
i := 0
for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
keys[i] = ent.Value.(*entry).key
i++
}
return keys
}
// Len returns the number of items in the cache.
func (c *LRU) Len() int {
return c.evictList.Len()
}
// Resize changes the cache size.
func (c *LRU) Resize(size int) (evicted int) {
diff := c.Len() - size
if diff < 0 {
diff = 0
}
for i := 0; i < diff; i++ {
c.removeOldest()
}
c.size = size
return diff
}
// removeOldest removes the oldest item from the cache.
func (c *LRU) removeOldest() {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent)
}
}
// removeElement is used to remove a given list element from the cache
func (c *LRU) removeElement(e *list.Element) {
c.evictList.Remove(e)
kv := e.Value.(*entry)
c.betterMap.DelKey(kv.key)
if c.onEvict != nil {
c.onEvict(kv.key, kv.value)
}
}`
The text was updated successfully, but these errors were encountered:
go map has a memory leak,can help fix it?
I now use two go map to fix it, if not use this way to avoid the memory leak problem
the reason is that go map delete a key only to label it ,but not really delete it, so the memory can increase always. Using the two map way sets the go map to nil that solves the problem.
`package simplelru
type BetterMap struct {
firstMap map[interface{}]interface{}
secondMap map[interface{}]interface{}
deleteNumThresh int32
totalDeleteNum int32
useMapIndex int32
}
func NewBetterMap(deleteNumThresh int32) *BetterMap {
return &BetterMap{
firstMap: make(map[interface{}]interface{}, 0),
secondMap: make(map[interface{}]interface{}, 0),
deleteNumThresh: deleteNumThresh,
totalDeleteNum: 0,
useMapIndex: 1,
}
}
func (bmap *BetterMap) Set(key interface{}, value interface{}) {
if bmap.useMapIndex == 1 {
bmap.firstMap[key] = value
} else {
bmap.secondMap[key] = value
}
}
func (bmap *BetterMap) GetValue(key interface{}) (interface{}, bool) {
if value, ok := bmap.firstMap[key]; ok {
return value, ok
}
}
func (bmap *BetterMap) GetValues() []interface{} {
values := make([]interface{}, 0)
if bmap.useMapIndex == 1 {
for _, value := range bmap.firstMap {
values = append(values, value)
}
} else {
for _, value := range bmap.secondMap {
values = append(values, value)
}
}
}
func (bmap *BetterMap) GetMap() map[interface{}]interface{} {
if bmap.useMapIndex == 1 {
return bmap.firstMap
}
}
func (bmap *BetterMap) GetLen() int {
if bmap.useMapIndex == 1 {
return len(bmap.firstMap)
}
}
func (bmap *BetterMap) Purge() {
bmap.firstMap = nil
bmap.secondMap = nil
}
func (bmap *BetterMap) DelKey(key interface{}) {
if bmap.useMapIndex == 1 {
delete(bmap.firstMap, key)
bmap.totalDeleteNum++
if bmap.totalDeleteNum >= bmap.deleteNumThresh {
bmap.secondMap = make(map[interface{}]interface{}, len(bmap.firstMap))
for i, v := range bmap.firstMap {
bmap.secondMap[i] = v
}
}
package simplelru
import (
"container/list"
"errors"
)
// EvictCallback is used to get a callback when a cache entry is evicted
type EvictCallback func(key interface{}, value interface{})
// LRU implements a non-thread safe fixed size LRU cache
type LRU struct {
size int
evictList *list.List
//items map[interface{}]*list.Element
betterMap *BetterMap
onEvict EvictCallback
}
// entry is used to hold a value in the evictList
type entry struct {
key interface{}
value interface{}
}
// NewLRU constructs an LRU of the given size
func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
if size <= 0 {
return nil, errors.New("Must provide a positive size")
}
c := &LRU{
size: size,
evictList: list.New(),
betterMap: NewBetterMap(int32(size)),
onEvict: onEvict,
}
return c, nil
}
// Purge is used to completely clear the cache.
func (c *LRU) Purge() {
c.betterMap.Purge()
c.betterMap = NewBetterMap(int32(c.size))
c.evictList.Init()
}
// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *LRU) Add(key, value interface{}) (evicted bool) {
// Check for existing item
if ent, ok := c.betterMap.GetValue(key); ok {
c.evictList.MoveToFront(ent.(*list.Element))
}
// Get looks up a key's value from the cache.
func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
}
// Contains checks if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
func (c *LRU) Contains(key interface{}) (ok bool) {
_, ok = c.betterMap.GetValue(key)
return ok
}
// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
}
// Remove removes the provided key from the cache, returning if the
// key was contained.
func (c *LRU) Remove(key interface{}) (present bool) {
if ent, ok := c.betterMap.GetValue(key); ok {
c.removeElement(ent.(*list.Element))
return true
}
}
// RemoveOldest removes the oldest item from the cache.
func (c *LRU) RemoveOldest() (key, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent)
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return nil, nil, false
}
// GetOldest returns the oldest entry
func (c *LRU) GetOldest() (key, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return nil, nil, false
}
// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *LRU) Keys() []interface{} {
keys := make([]interface{}, c.betterMap.GetLen())
i := 0
for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
keys[i] = ent.Value.(*entry).key
i++
}
return keys
}
// Len returns the number of items in the cache.
func (c *LRU) Len() int {
return c.evictList.Len()
}
// Resize changes the cache size.
func (c *LRU) Resize(size int) (evicted int) {
diff := c.Len() - size
if diff < 0 {
diff = 0
}
for i := 0; i < diff; i++ {
c.removeOldest()
}
c.size = size
return diff
}
// removeOldest removes the oldest item from the cache.
func (c *LRU) removeOldest() {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent)
}
}
// removeElement is used to remove a given list element from the cache
func (c *LRU) removeElement(e *list.Element) {
c.evictList.Remove(e)
kv := e.Value.(*entry)
c.betterMap.DelKey(kv.key)
if c.onEvict != nil {
c.onEvict(kv.key, kv.value)
}
}`
The text was updated successfully, but these errors were encountered: