lonelyenvoy / python-memoization

A powerful caching library for Python, with TTL support and multiple algorithm options.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Memoization does not release memory after cache_clear

eldernewborn opened this issue · comments

Looking at the profiler output, it seems like cached decorator is not releasing memory:

    32   2578.6 MiB      0.0 MiB           1       c = MemoizeClass()
    33   2829.4 MiB      0.0 MiB        1001       for i in range(1000):
    34   2829.4 MiB    250.8 MiB        1000           c.get_something(random.randint(0, 4000000000000))
    35   2829.4 MiB      0.0 MiB           1       print(c.get_something.cache_info())
    36   2829.5 MiB      0.1 MiB           1       print(len(list(c.get_something.cache_items())))
    37   2829.5 MiB      0.0 MiB           1       print("############## flushing the cache ################")
    38   2829.5 MiB      0.0 MiB           1       c.get_something.cache_clear()
    39   2829.5 MiB      0.0 MiB           1       print(len(list(c.get_something.cache_items())))
    40   2829.5 MiB      0.0 MiB           1       print(c.get_something.cache_info())
    41   2829.5 MiB      0.0 MiB           1       print(f"found some Garbage:{len(gc.garbage)} items")
    42   2829.5 MiB      0.0 MiB           1       print(f"collected: {gc.collect()}")

environment :
python 3.9.5
memoization: 0.4.0

code to reproduce the results. run with pytest -s for best results.

from memory_profiler import profile
import gc
from memoization import cached
import random
import hashlib


class MemoizeClass:
    def __int__(self):
        self.unique = random.randint(0, 4000000000000)

    @cached(max_size=1362)
    def get_something(self, param):
        return [param] * (2*10**5)
@profile
def test_memoization_cache():
    print("\n")
    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())

    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())

    del c
    print(f"found some Garbage:{len(gc.garbage)} items")
    print(f"collected: {gc.collect()}")

    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())
    print(len(list(c.get_something.cache_items())))
    print("############## flushing the cache ################")
    c.get_something.cache_clear()
    print(len(list(c.get_something.cache_items())))
    print(c.get_something.cache_info())
    print(f"found some Garbage:{len(gc.garbage)} items")
    print(f"collected: {gc.collect()}")

    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())

Comparing the behavior with functools :

    32   2702.9 MiB      0.0 MiB           1       c = MemoizeClass()
    33   2832.9 MiB -50638.2 MiB        1001       for i in range(1000):
    34   2832.9 MiB -50508.2 MiB        1000           c.get_something(random.randint(0, 4000000000000))
    35   2802.4 MiB    -30.5 MiB           1       print(c.get_something.cache_info())
    36   1661.3 MiB  -1141.1 MiB           1       c.get_something.cache_clear()
    37   1661.3 MiB      0.0 MiB           1       print("############## flushing the cache ################")
    38   1661.3 MiB      0.0 MiB           1       print(c.get_something.cache_info())
    39   1661.3 MiB      0.0 MiB           1       print(f"found some Garbage:{len(gc.garbage)} items")
    40   1661.3 MiB      0.0 MiB           1       print(f"collected: {gc.collect()}")

Same environment
Code:

from memory_profiler import memory_usage,profile
import gc
from functools import lru_cache
import random
import hashlib

class MemoizeClass:
    def __int__(self):
        self.unique = random.randint(0, 4000000000000)

    @lru_cache(maxsize=1362)
    def get_something(self, param):
        return [param] * (2*10**5)

@profile
def test_memoization_cache():
    print("\n")
    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())

    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())

    del c
    print(f"found some Garbage:{len(gc.garbage)} items")
    print(f"collected: {gc.collect()}")

    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())
    c.get_something.cache_clear()
    print("############## flushing the cache ################")
    print(c.get_something.cache_info())
    print(f"found some Garbage:{len(gc.garbage)} items")
    print(f"collected: {gc.collect()}")

    c = MemoizeClass()
    for i in range(1000):
        c.get_something(random.randint(0, 4000000000000))
    print(c.get_something.cache_info())