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

Memory Leak on MacOS #670

Open
peterallenwebb opened this issue Mar 20, 2024 · 2 comments
Open

Memory Leak on MacOS #670

peterallenwebb opened this issue Mar 20, 2024 · 2 comments

Comments

@peterallenwebb
Copy link

Calling the keyring.get_password() function repeatedly on MacOS results in leaked memory. The problem appears to be in find_generic_password(), where the memory allocated by SecItemCopyMatching() is never released. I spent some time trying to fix the issue, but it was dragging me further into the world of CoreFoundation internals than I had time to go.

I don't know how serious the problem is in practice, but using memray I was seeing a non-negligible memory allocation (~30MB) hanging around in my application, attributable to this function.

Thank you so much for your work maintaining this library! If I have more time soon I might return to the issue and attempt a fix.

@jaraco
Copy link
Owner

jaraco commented Mar 23, 2024

Thanks for reporting. Sounds like a bug to me. I'm also not exactly familiar with the object lifecycle management in CoreFoundation, so I welcome your contrib (or someone else). If someone starts on it, let me know so I can assign the issue to you and avoid duplication of work.

@patrick-kidger
Copy link

patrick-kidger commented Nov 20, 2024

Hi folks. I've just bumped into this, and I think I've tracked this down. MWE:

import gc
import weakref

ref = None

class MyVeryLargeObject:
    pass

def f():
    global ref
    x = MyVeryLargeObject()
    ref = weakref.ref(x)
    import keyring.backends.Windows

f()
gc.collect()
print(ref())  # <__main__.MyVeryLargeObject object at 0x101611f10>

The issue is because this exception trap:

with ExceptionTrap() as missing_deps:

is holding on to the exception at the global level forever. This exception keeps a reference to the current traceback, and that tracebacks keeps references to all the local variables up the stack.

Replacing import keyring.backends.Windows with keyring.get_password() reproduces the same behaviour, I assume it's doing a dynamic import internally.

I'm not suitably familiar with keyring to offer a PR, but hopefully this helps :)

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

No branches or pull requests

3 participants