8298084: Memory leak in Method::build_profiling_method_data #13
Conversation
👋 Welcome back coleenp! A progress list of the required criteria for merging this PR into |
Webrevs
|
@coleenp Unknown command |
/help |
@coleenp Available commands:
|
/contributor add @jcking |
@coleenp |
@coleenp 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 11 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 |
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.
Thanks Erik and Kim. @TobiHartmann and @jcking, do you want to review? |
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.
Not sure about some of the incidental changes - see below.
Thanks.
if (release_sub_metadata) { | ||
methods_do(method_release_C_heap_structures); | ||
} |
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 don't understand this aspect of the change. It seems unrelated to the missing destructor issue and seems to cause a significant change in behaviour as we will no longer call methods_do
when called from deallocate_contents
with the renamed false
argument.
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.
This boolean prevents us from calling the MethodData destructor twice and releasing MethodData C heap memory twice. InstanceKlass::deallocate_contents calls release_C_heap_structures with it false, and then calls through the Metadata pointer hierarchy to MetadataFactory::free_metadata, which calls the MethodData destructor and MethodData::deallocate_contents which calls MethodData::release_C_heap_structures(). This is the delegation scheme for releasing metadata between InstanceKlass and ConstantPool.
InstanceKlass::release_C_heap_structures() is also called during class unloading and must walk the whole metadata, releasing C heap memory. It's passed true. It doesn't go through deallocate_contents because the metadata is freed together at the same time with the metaspace that contains it.
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 Coleen I see now how the code has been shuffled around:
Old code:
InstanceKlass::deallocate_contents
-> release_C_heap_structures(/* release_sub_metadata */ false);
-> methods_do(method_release_C_heap_structures);
-> m->release_C_heap_structures
-> method_data()->~MethodData();
-> deallocate_methods(loader_data, methods());
-> MetadataFactory::free_metadata(loader_data, method);
New code:
InstanceKlass::deallocate_contents
-> release_C_heap_structures(/* release_sub_metadata */ false);
-> deallocate_methods(loader_data, methods());
-> MetadataFactory::free_metadata(loader_data, method);
-> method_data()->~MethodData();
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.
Yes, plus releasing the JVMCI thing that MethodData points to also.
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 Coleen. A couple of further nits on comments but otherwise this seems okay.
// Can't release the constant pool here because the constant pool can be | ||
// deallocated separately from the InstanceKlass for default methods and | ||
// redefine classes. |
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.
Does this comment make sense when the parameter doesn't actually control release of the CP?
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.
The comment means it can't release constant pool CHeap structures. It should be inclusive of MethodData also.
@@ -2665,12 +2665,14 @@ static void method_release_C_heap_structures(Method* m) { | |||
} | |||
|
|||
// Called also by InstanceKlass::deallocate_contents, with false for release_constant_pool. |
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.
Comment needs updating.
if (release_sub_metadata) { | ||
methods_do(method_release_C_heap_structures); | ||
} |
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 Coleen I see now how the code has been shuffled around:
Old code:
InstanceKlass::deallocate_contents
-> release_C_heap_structures(/* release_sub_metadata */ false);
-> methods_do(method_release_C_heap_structures);
-> m->release_C_heap_structures
-> method_data()->~MethodData();
-> deallocate_methods(loader_data, methods());
-> MetadataFactory::free_metadata(loader_data, method);
New code:
InstanceKlass::deallocate_contents
-> release_C_heap_structures(/* release_sub_metadata */ false);
-> deallocate_methods(loader_data, methods());
-> MetadataFactory::free_metadata(loader_data, method);
-> method_data()->~MethodData();
// Call the destructor. This is currently used for MethodData which has a member | ||
// that needs to be destructed to release resources. Most Metadata derived classes have noop | ||
// destructors and/or cleanup using deallocate_contents. | ||
// T is a potentially const or volatile qualified pointer. Remove any const |
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.
We'll given the template, T by itself is no longer a pointer so its just potentially const or volatile qualified. But that is pedantic.
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 just want to leave it because you're right but pointer is a readable noun here.
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 to me. Thanks for fixing!
Thanks for the reviews David, Justin and Tobias. |
Going to push as commit 04b8d0c.
Your commit was automatically rebased without conflicts. |
This change fixes the MethodData leak by calling the destructor in both the release_C_heap_structures conditionally and by calling the MethodData destructor in the MetadataFactory::free_metadata method.
Thanks to @jcking for working on the patch and discussion.
Tested with tier1-4.
Progress
Issue
Reviewers
Contributors
<jcking@openjdk.org>
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk20 pull/13/head:pull/13
$ git checkout pull/13
Update a local copy of the PR:
$ git checkout pull/13
$ git pull https://git.openjdk.org/jdk20 pull/13/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 13
View PR using the GUI difftool:
$ git pr show -t 13
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk20/pull/13.diff