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
JDK-8259710: Inlining trace leaks memory #2063
JDK-8259710: Inlining trace leaks memory #2063
Conversation
👋 Welcome back stuefe! A progress list of the required criteria for merging this PR into |
Webrevs
|
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.
Otherwise, looks good to me.
@tstuefe This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 180 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
Thanks Tobias. I added your suggestion. Cheers, Thoams |
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.
Thanks for updating. Looks good but you accidentally pushed make/hs_err_pid10680.log
, make/replay_pid10680.log
:)
Best regards,
Tobias
Oops. Corrected. Not my day today :) |
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.
Looks good.
Thank you Nils! |
GA errors seem unrelated, and this patch runs in our SAP internal tests since a week without problems. /integrate |
@tstuefe Since your change was applied there have been 180 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit ca20c63. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
We see C-heap leaking, originating in C2:
accumulating over the course of days to some hundred MB at a customer site where inline tracing was active.
Analysis:
To build up a comprehensive inlining trace, c2 keeps trace snippets in an internal list and assembles them at print time. These are stringStream's, contained in PrintInliningBuffer:
With JDK-8224193, stringStream was changed to use C-heap instead of ResourceArea for its internal buffer. This means one cannot just omit stringStream destruction anymore - even where stringStream objects themselves live in RA, their internal buffers don't, they live in C-Heap. To clean up properly, ~stringStream() must be called.
Those
PrintInliningBuffer
objects are kept by value in a GrowableArrayCompile::_print_inlining_list
. Normally, if an object is kept by value, it needs to implement correct copy- and destruction-semantics. PrintInliningBuffer does not do that and instead relies on manual cleanup (PrintInliningBuffer::freeStream()
) - I assume the authors did not want to deal with reference counting the contained stringStream on copying.That however is a problem because GrowableArray creates internally temporary objects of the item type to pre-populate its array - its whole capacity - when it grows:
this it does for the whole new capacity, which means more objects get created than have been added; if the caller does not fill the GrowableArray up to its capacity, it never knows about the excess objects created. This is normally not a problem since all these objects are destructed by GrowableArray in
void GrowableArrayWithAllocator<E, Derived>::clear_and_deallocate()
. But since PrintInliningBuffer does not implement a destructor, this has no effect.PrintInliningBuffer instead relies on manual cleanup of the stringStreams: at the end of the compile phase, it calls
PrintInliningBuffer::freeStream()
on all buffers it thinks are contained in the array:but this of course leaves the excess objects untouched (objects whose index is array length >= index >= array capacity).
There are several ways to fix this:
implement correct destructor- and copy semantics for PrintInliningBuffer. This would work but is not optimal since we would still pay for creation of unnecessary PrintInliningBuffer objects when the array is prepopulated on grow()
delay construction of
PrintInliningBuffer::_ss
until the stream is actually used for writing into. This would would mean we have to check the stringStream for NULL before using it.Just let the PrintInliningBuffer live in C-heap instead of the RA. Its only a small shell anywhere now that the stringStream buffer lives in C-heap. Instead, let PrintInliningBuffer contain the stringStream as a member, allocate PrintInliningBuffer from C-heap, and change the list to contain pointers to PrintInliningBuffer, not the object itself. This removes all that unnecessary copying, removes creation of temporary objects, and simplifies the code. Having to free those objects is no big deal since we free the stringStream objects manually anyway.
I went with (3). I also decreased the default stringStream buffer size for this scenario since when testing I found out that many trace snippets are below 128 bytes.
Note that (3) is not only simpler, but also more efficient: many of the PrintInliningBuffer objects are inserted into the middle of the _print_inlining_list; GrowableArray does shift all higher items up to provide space for the new item. If those items are simple pointers instead of whole objects, less memory is moved around.
Tests:
Thanks, Thomas
Progress
Issue
Reviewers
Download
$ git fetch https://git.openjdk.java.net/jdk pull/2063/head:pull/2063
$ git checkout pull/2063