-
Notifications
You must be signed in to change notification settings - Fork 84
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
Don't depend on the GC to free native memory on Linux #151
base: master
Are you sure you want to change the base?
Conversation
adff2b9
to
bb88ffb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate your time and effort, @avrecko, but there are some parts of this I can't accept. I'd like to see it stripped back to a change that's more targeted to freeing the buffers, without some of the other changes, before I could accept it.
If you want to move forward with upgrading JNA to 5.13, using a single buffer allocation, adding an explicit free
for it, and potentially keeping your IntByReference
tweak, those changes can be pretty readily accepted. The rest, while perhaps beneficial to certain use cases, penalizes others.
src/main/java/com/zaxxer/nuprocess/internal/BaseEventProcessor.java
Outdated
Show resolved
Hide resolved
bb88ffb
to
c06bd4d
Compare
@bturner What are your thoughts on explicitly freeing the per process EpollEvent on call to onExit()? The complication is that some synchronization guards are needed to avoid any API misuse that can cause SegFault. E.g. |
Also what are you thoughts of making the buffer configurable? Like a global setting? |
For this review, I'd leave it out. Synchronization brings in its own costs that need to be balanced. I'm not saying we shouldn't do it, but rather that it's better to separate "contentious" changes from the simple ones that can be readily merged. That way I can accept this pull request and do a new release with some improvements, and then we can have a more focused discussion about further improvements and the trade-offs they entail.
I'm not sure what buffer you're referring to. The size for the |
Ok agreed. I'll put the explicit close of per process EpollEvent in another
pull request.
Yeah, I saw the offset handling regarding the EPoll struct. Wow. Didn't
image JNA to be this inefficient to merit doing it yourself with offsets.
Not very convenient then.
fwiw: doing some simple testing also not seeing the benefit of polling 20
instead of 1 event. I do consistently see 2 events queried. But anyway, for
now I left the poll alone.
For the configuration I meant for setting of NuProcess#BUFFER_CAPACITY. For
my use case, I think 4K would work just fine.
I'll clean up the code and let you know when it is ready to be reviewed
again.
V V pon., 12. feb. 2024 ob 19:23 je oseba Bryan Turner <
***@***.***> napisala:
… What are your thoughts on explicitly freeing the per process EpollEvent on
call to onExit()?
For this review, I'd leave it out. Synchronization brings in its own costs
that need to be balanced. I'm not saying we shouldn't do it, but rather
that it's better to separate "contentious" changes from the simple ones
that can be readily merged. That way I can accept this pull request and do
a new release with some improvements, and then we can have a more focused
discussion about further improvements and the trade-offs they entail.
Also what are you thoughts of making the buffer configurable? Like a
global setting?
I'm not sure what buffer you're referring to. The size for the stderr,
stdout and stdin buffers? Something else?
—
Reply to this email directly, view it on GitHub
<#151 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACRDOL5KOPXAAXLVQ57V3TYTJMZ7AVCNFSM6AAAAABDDYRJMOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSMZZGI4TMNJVHE>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
That matches what I saw before. I could see >1 event being returned, but performance and profiling characteristics were identical either way. (Polling for more can reduce the number of syscalls, but since handler processing dominates the performance so strongly, taking away milliseconds (or, more likely, nanoseconds) of syscall execution simply doesn't move the needle.) Based on that, I think leaving it at single poll is probably fine (and keeps the code simpler).
Brett and I had previously at least touched on the idea of making that configurable (see here). A system property approach would be pretty straightforward, so it might be a good place to start. I've thought before about what might be involved in making it more readily runtime-configurable (e.g. so that, when you start a process, you can request a buffer size as part of that, because not all processes have the same I/O needs), but haven't actually sat down to try and do it. |
c06bd4d
to
897f9b6
Compare
Have same thoughts about setting of out/err/in buffer sizes. I'll prepare
another pull request for system property approach. I also think it is a
good place to start. For more fine grained control, process builder is
probably the place to add it. But maybe unnecessary.
|
@bturner I think this is it. Updated JNA to get the #close method, out/err/in buffers are closed and added the tweak to reuse IntByReference pointer by the epoll/kqueue. Btw: wow, the Kqueue is using the Struct KEvent, indeed it is heavy. I expected some bespoke code generators from JNA. Not even close. I still have my eyes on the per process Event allocation that isn't freed right away. I'll think of something. |
d3432ce
to
2f9ac1b
Compare
For the per process event. I know you'd prefer to do this in a different PR. But I think I came up with a solution that is simple enough. Event is needed by the For the registration. We can allocate the event and free right away inside the registration method. This way the per process event is not needed. If you don't do stdin stuff no further allocations are necessary. For stdin handling. I prefer on demand init of the event that is then used by calling wantWrite and writeStdin. Technically multiple threads can call wantWrite and writeStdin. But the race is not an issue since all threads are setting the same values that are atomic (on x86 at least).
If 2 threads would be calling Apart from on demand per process init of Event when doing Let me know what you think. Like mentioned I want all of the malloc stuff to be explicity freed when process exits. With this changes this is achieved for Aside: Expected |
2f9ac1b
to
cf8efd5
Compare
That approach doesn't really make sense to me, unfortunately.
For point 1, if we're not massively concerned about allocating a few For point 2, if we don't want to allocate an If we're going to add a new method, I don't think it's "correct" to add it just to Personally, at this point, I'm inclined to go with "just" allocating |
src/main/java/com/zaxxer/nuprocess/internal/BaseEventProcessor.java
Outdated
Show resolved
Hide resolved
cf8efd5
to
3eed929
Compare
@bturner If you are cool with allocating/freeing per I think JNA and also JNI does some small allocations per method call anyway. So probably not a big deal if we do as well. |
I've updated the title to be less generic and updated the first comment of this PR. I've updated the code to reflect the latest discussion. |
fdb75cc
to
081d81e
Compare
@bturner I left the Leaving To reiterate the problem I am solving. In some GC setups. It might take hours between GC cycles that trigger reference processing. In this time nonnegligible amouth of native memory accumulate that cause native memory issues. See: https://mail.openjdk.org/pipermail/zgc-dev/2023-August/001260.html |
JNA is freeing 192 KiB of per NuProcess native buffers on GC Finalizer / Reference Queue processing. In cases with very low GC activity, this is essentially a memory leak, potentially causing native memory issues. * out/err/in buffers are freed onExit, * event needed for Epoll #registerProcess and ##queueWrite is allocated and freed in the method, * tweak in reusing of IntByReference for duration of epoll/kqueue processor, * updated JNA library to 5.13.0, to get #close on Memory object (added in 5.12.0).
081d81e
to
09350c5
Compare
JNA is freeing 192 KiB of per NuProcess native buffers on GC Finalizer / Reference Queue processing. In cases with very low GC activity, this is essentially a memory leak, potentially causing native memory issues.