RFR: 8268406: Deallocate jmethodID native memory [v7]

David Holmes dholmes at openjdk.org
Thu Jun 19 00:44:30 UTC 2025


On Wed, 18 Jun 2025 12:46:56 GMT, Coleen Phillimore <coleenp at openjdk.org> wrote:

>> This change uses a ConcurrentHashTable to associate Method* with jmethodID, instead of an indirection.  JNI is deprecated in favor of using Panama to call methods, so I don't think we're concerned about JNI performance going forward.  JVMTI uses a lot of jmethodIDs but there aren't any performance tests for JVMTI, but running vmTestbase/nsk/jvmti with in product build with and without this change had no difference in time.
>> 
>> The purpose of this change is to remove the memory leak when you unload classes: we were leaving the jmethodID memory just in case JVMTI code still had references to that jmethodID and instead of crashing, should get nullptr.  With this change, if JVMTI looks up a jmethodID, we've removed it from the table and will return nullptr.  Redefinition and the InstanceKlass::_jmethod_method_ids is somewhat complicated.  When a method becomes "obsolete" in redefinition, which means that the code in the method is changed, afterward creating a jmethodID from an "obsolete" method will create a new entry in the InstanceKlass table.  This mechanism increases the method_idnum to do this.  In the future maybe we could throw NoSuchMethodError if you try to create a jmethodID out of an obsolete method and remove all this code.  But that's not in this change.
>> 
>> Tested with tier1-4, 5-7.
>
> Coleen Phillimore has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Add a basic gtest.

Still working my way through this ...

Just to be sure I have the correct mental picture of this, things work as follow:

- a `jMethodID` is just a unique integer index to represent a `Method` for use with JNI
- when we allocate a new `jMethodID` to a `Method` we 
  - add that mapping to the global table
  - add an entry to the `ClassLoaderData`'s `jMethodID` "list"
- each `instanceklass` also maintains a "cache" of its own `jMethodID` mappings (some of which need updating on method redefinition)
- when a class is unloaded we deallocate the cache, deallocate the CLD list, and remove the table entries
- when a JNI API is presented with a `jMethodID` by the caller, it validates it by looking it up in the table, to see if the mapping exists

The cache is created under a lock, and `jMethodID`s are created and added to the cache (and the table, and the CLD list) under the same lock. But access to the cache is lock-free using acquire/release.

The cache is also destroyed under the same lock, and the table entries removed under that same lock, and the CLD list deallocated.

Is the above correct? What details have I missed?

Thanks

src/hotspot/share/oops/instanceKlass.cpp line 2395:

> 2393: 
> 2394: // Allocate the jmethodID cache.
> 2395: static jmethodID* create_jmethod_id_cache(size_t size) {

Why isn't this used at line 2439 to create the (initial?) cache?

src/hotspot/share/oops/jmethodIDTable.cpp line 40:

> 38: static uint64_t _jmethodID_counter = 0;
> 39: // Tracks the number of jmethodID entries in the _jmethod_id_table.
> 40: // Incremented on insert, decremented on remove. Use to track if we need to resize the table.

Suggestion:

// Incremented on insert, decremented on remove. Used to track if we need to resize the table.

src/hotspot/share/oops/jmethodIDTable.cpp line 141:

> 139:   // Update jmethodID global counter.
> 140:   _jmethodID_counter++;
> 141:   guarantee(_jmethodID_counter != 0, "must never go back to zero");

Again a guarantee is not needed here as the only possible way this could trigger is if we initialize it incorrectly./

-------------

PR Review: https://git.openjdk.org/jdk/pull/25267#pullrequestreview-2940758855
PR Review Comment: https://git.openjdk.org/jdk/pull/25267#discussion_r2155747747
PR Review Comment: https://git.openjdk.org/jdk/pull/25267#discussion_r2155550987
PR Review Comment: https://git.openjdk.org/jdk/pull/25267#discussion_r2155763677


More information about the hotspot-dev mailing list