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

BUG: Memory Leak in _GenericBinaryOutFunction #7482

Merged
merged 1 commit into from
Jun 5, 2016

Conversation

simongibbons
Copy link
Contributor

_GenericBinaryOutFunction was leaking constructing a string
each time it was called which wasn't deallocated on some
versions of python (due to string interning rules). This
fixes this by storing the **kwargs that are passed into
the op statically so that they are only constructed
the first time that _GenericBinaryOutFunction is called.

Credit to @seberg for finding the location of the
bug and providing an initial version of the fix.

Fixes #6672

@simongibbons
Copy link
Contributor Author

Oh given this bug is a memory leak (and a small one at that) I'm not entirely sure how to write a regression test for this. Any ideas?

if (kw == NULL) {
Py_DECREF(args);
return NULL;
kw = PyDict_New();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not build the dictionary with Py_BuildValue and spare ourselves all the trouble?

kw = Py_BuildValue("{s:s}", "casting", "unsafe");

@simongibbons
Copy link
Contributor Author

Yup you're right - that really does simplify things. I'm not sure why I thought Py_BuildValue could only create tuples.

@jaimefrio
Copy link
Member

It is not very explicit in the prose of the documentation, which mostly discusses single objects vs tuples, but it lets you build single objects, tuples (), lists [] or dicts {}.

@simongibbons
Copy link
Contributor Author

Right, looks like the build is passing with that change. Like I said a test for this is tricky - if you're ok without putting one in for this then I think this may be ready for merging. It just needs me to squash the commits (and clean up the fairly horrendous english in the commit message - really should have proof read that!)

@jaimefrio
Copy link
Member

I would like to know if using Py_BuildValue without a making the dict static we still have the leak: I don't fully understand what the "different string interning rules" that @seberg figured were the cause of the leak mean exactly, which makes me a little uneasy.

But it probably makes sense making that dict static regardless, so we don't have to recreate it every time. So go ahead and leave it squashed an ready to merge, and if no one comes up with a good explanation or testing idea we'll put it in as is.

@seberg
Copy link
Member

seberg commented Mar 30, 2016

The string interning is not really the cause of the leak, it is just the cause of the reference leak being visible as a memory leak in some python versions and not in others.

_GenericBinaryOutFunction was leaking a string each time it was called.
This fixes the leak by storing the (constant) **kwargs that are passed
into the op statically so that they are only constructed the first
time that _GenericBinaryOutFunction is called.

Credit to @seberg for finding the location of the bug and providing
an initial version of the fix.
@charris
Copy link
Member

charris commented Jun 4, 2016

@seberg Is more needed here?

@seberg
Copy link
Member

seberg commented Jun 5, 2016

No, I think this is fine (tests are probably annoying to figure out). Thanks for the ping and thanks @simongibbons.

@seberg seberg merged commit f65b233 into numpy:master Jun 5, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

memory leak in np.clip()
4 participants