-
-
Notifications
You must be signed in to change notification settings - Fork 797
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
Figure out why LockFreePool
appears to cause unintended object retention (~= memory leak)
#1260
Comments
/cc @mariofusco @pjfanning -- I hope to learn if there is some specific usage scenario and create multi-threaded reproduction. I am suspecting that somehow reuse from the pool is failing, but perhaps not for every call. Also: it is interesting that the one concern I did have wrt unbounded pools ended up happening, it seems. |
HI @cowtowncoder I would like to investigate this memory issue, but at the moment I have no clue on how to reproduce it on my side. I also asked here and I'm waiting for an answer. I'm reviewing its implementation again, and in all honesty it seems quite straightforward, so at the moment I don't know what to do about it. About making the LockFree pool bounded, this is of course feasible, but I'm against for a few reasons:
|
Thinking twice, now I see an admittedly weird situation where the LockFree pool can grow indefinitely. In that pool there is an heuristic to limit the number of retries under heavy contention. When this happens it gives up attempting to retrieve a resource from the pool and creates a new one instead. However this heuristic is implemented symmetrically on both acquire and release, so similarly on release it gives up trying to put back a resource into the pool after a few failed attempts. In essence the pool will grow if there is a huge asymmetry in its usage, when the acquire is always under heavy contention but the release isn't. I'm not sure how to deal with this situation to be honest, but still I would like to see it happens into the wild before deciding on any action. |
@mariofusco Your thoughts align remarkably closely with my thinking :) As to reproduction, what I was thinking was indeed running a multi-threaded scenario with N threads, reading and writing, against modified copy of pool which allows accessing size, printing it periodically and checking if size would be growing. As to adding bounded size: I 100% agree that we need to understand the problem first and not add something that would likely just hide the problem. |
I am now reading past the issues and probably giving up on contention is not what we want. Anothe solution can be to spread the contention or uses better primitives which "cannot fail" eg getAndSet But that means redesigning what it does; just serialising while too contended seems the easier choice to me. |
I may be wrong, but to me it seems like |
@mariofusco @franz1981: I created #1265 which sort of hints at possible problem, but isn't smoking gun necessarily. When running through 3 main implementations, So no, this does not show monotonically increasing behavior, but suggests that spikes are possible. But if anyone else has time to run test, and/or read code and suggest changes, that'd be useful. |
Yet another report with "memory leak" reproduction: https://github.com/kkolyan/jackson_leak. |
@kkolyan Thank you very much for creating this! I hope to try it out locally, and see if the other 2 implementations (and in particular, Deque backed ones) fared better. EDIT: looks like it's not trivial to change impl to measure other impls due to |
…blem with pool retention (#1265)
…blem with pool retention (#1265)
@kkolyan Trying to run the reproduction, but since I am not a gradle user, not sure what invocation is expected. Guessing from
neither of which works (build succeeds with Also had to add |
I'm able to run the test on IDE just fine. Not yet seeing much of a trend, assuming I read output correctly. But one related thing is this: I backported addition of
in
|
Ok, I think we have a reasonable idea as to how the retention may happen: due to imbalanced failures between acquiring reusable buffer (fails more often) vs releasing buffer to the pool (fails less often). |
Based on report problem like:
it looks as if the new recycler pool default (see #1117) -- Lock-free Pool -- results in (at least in some cases) unbounded increasing memory retention over time. From symptoms it would appear as if actual releases to pool happened more often than succesful reuse from the pool, as otherwise 2 operations should generally balance out over time (resulting in maximum pool size relative to maximum concurrent use).
We need to figure out what could cause such behavior, or if not, what is the root cause of observed problems.
In the meantime we also will need to do #1256 to allow use of 2.17(.1) without this issue.
The text was updated successfully, but these errors were encountered: