Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go map has a memory leak,can help fix it? #107

Open
xuetusc opened this issue Sep 26, 2022 · 0 comments
Open

go map has a memory leak,can help fix it? #107

xuetusc opened this issue Sep 26, 2022 · 0 comments

Comments

@xuetusc
Copy link

xuetusc commented Sep 26, 2022

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
}

value, ok := bmap.secondMap[key]

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)
}
}

return values

}

func (bmap *BetterMap) GetMap() map[interface{}]interface{} {
if bmap.useMapIndex == 1 {
return bmap.firstMap
}

return bmap.secondMap

}

func (bmap *BetterMap) GetLen() int {
if bmap.useMapIndex == 1 {
return len(bmap.firstMap)
}

return len(bmap.secondMap)

}

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
}

		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)
}
}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant