prompt-toolkit / python-prompt-toolkit

Library for building powerful interactive command line applications in Python
https://python-prompt-toolkit.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
9.28k stars 715 forks source link

[fix memory leak]PromptSession wouldn't free #1743

Closed vicalloy closed 1 year ago

vicalloy commented 1 year ago

Reference: https://github.com/prompt-toolkit/python-prompt-toolkit/issues/1688

I updated to the latest python-prompt-toolkit and found that it still has memory leaks. It's seems that the default AppSession in _current_app_session holds some Filter objects and indirectly holds PromptSession objects. If I remove is_done and Always from filter's cache, PromptSession objects can be freed. I added a can_cache argument to Filter to prevent is_done from being cached, and made Always a singleton. After these changes PromptSession can be freed.

Unresolved bug: If I called await session.prompt_async() one PromptSession is not freed.

import asyncio
import gc

from prompt_toolkit import PromptSession

async def create_session():
    try:
        session = PromptSession()
        # await session.prompt_async()
    except KeyboardInterrupt:
        print("pass")
    del session
    gc.collect()

async def m():
    for _ in range(5):
        await create_session()
    gc.collect()
    obj = gc.get_objects()
    print('len', len([o for o in obj if isinstance(o, PromptSession)]))

asyncio.run(m())