RFR: 8353273: Reduce number of oop map entries in instances

Thomas Stuefe stuefe at openjdk.org
Mon Mar 31 16:30:37 UTC 2025


In preparation for planned GC performance improvements (KLUT), I would like to reduce the average number of oop map entries.

For details, please see JBS issue text.

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

Patch results:

The patch brings a positive change of oop map size, reducing the likelihood of lengthy oop maps. Here the oop map size distribution over all JDK classes in the JDK image: 

Before:

   5395  - non-static oop maps (0 entries)
   9330  - non-static oop maps (1 entries)
   1449  - non-static oop maps (2 entries)
    274  - non-static oop maps (3 entries)
    218  - non-static oop maps (4 entries)
     75  - non-static oop maps (5 entries)
      7  - non-static oop maps (6 entries)
      4  - non-static oop maps (7 entries)


Now:

   5395  - non-static oop maps (0 entries)
  10178  - non-static oop maps (1 entries)
    933  - non-static oop maps (2 entries)
    229  - non-static oop maps (3 entries)
     16  - non-static oop maps (4 entries)
      1  - non-static oop maps (5 entries)


For example, `java.util.concurrent.ConcurrentHashMap$TreeNode` is changed from having 2 entries to having just one entry, which is nice for a class that may be instantiated a lot:

Before:

java.util.concurrent.ConcurrentHashMap$TreeNode {0x000000000d1dddc0}
 - ---- non-static fields (9 words):
 - final 'hash' 'I' @12
 - final 'key' 'Ljava/lang/Object;' @16 
 - volatile 'val' 'Ljava/lang/Object;' @20 
 - volatile 'next' 'Ljava/util/concurrent/ConcurrentHashMap$Node;' @24       << last field of base class
 - 'red' 'Z' @28                                                             << derived class starts here, non-oops lead
 - 'parent' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @32 
 - 'left' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @36 
 - 'right' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @40 
 - 'prev' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @44 
 - non-static oop maps (2 entries): 16-24 32-44  

Now:

java.util.concurrent.ConcurrentHashMap$TreeNode {0x000000007e1de450}
 - ---- non-static fields (9 words):
 - final 'hash' 'I' @12 
 - final 'key' 'Ljava/lang/Object;' @16 
 - volatile 'val' 'Ljava/lang/Object;' @20 
 - volatile 'next' 'Ljava/util/concurrent/ConcurrentHashMap$Node;' @24       << last field of base class
 - 'parent' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @28          << class starts here, oops lead
 - 'left' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @32 
 - 'right' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @36 
 - 'prev' 'Ljava/util/concurrent/ConcurrentHashMap$TreeNode;' @40 
 - 'red' 'Z' @44 
 - non-static oop maps (1 entries): 16-40 


Note how the sole primitive field of the derived class, "red", changed position to let oops lead.

Here a contrived example to demonstrate how reordering works across several inheritance levels:


Before:

GeneratedClass9730 {0x000000008f93ea50}
 - ---- non-static fields (11 words):
 - public 'derived0_I_0' 'I' @12 
 - public 'derived0_o_0' 'Ljava/lang/Object;' @16                            << last field of base class
 - public 'derived1_I_0' 'I' @20 
 - public 'derived1_o_0' 'Ljava/lang/Object;' @24                            << last field of derived class 1
 - public 'derived2_I_0' 'I' @28 
 - public 'derived2_o_0' 'Ljava/lang/Object;' @32                            << last field of derived class 2
 - public 'derived3_I_0' 'I' @36 
 - public 'derived3_o_0' 'Ljava/lang/Object;' @40                            << last field of derived class 3
 - public 'derived4_I_0' 'I' @44 
 - public 'derived4_o_0' 'Ljava/lang/Object;' @48                            << last field of derived class 4
 - public 'o0' 'Ljava/lang/Object;' @52                                      << this class starts here
 - non-static oop maps (5 entries): 16-16 24-24 32-32 40-40 48-52 


After

GeneratedClass9730 {0x00000000a793e5f8}
 - ---- non-static fields (11 words):
 - public 'derived0_I_0' 'I' @12 
 - public 'derived0_o_0' 'Ljava/lang/Object;' @16                            << last field of base class
 - public 'derived1_o_0' 'Ljava/lang/Object;' @20 
 - public 'derived1_I_0' 'I' @24                                             << last field of derived class 1
 - public 'derived2_I_0' 'I' @28 
 - public 'derived2_o_0' 'Ljava/lang/Object;' @32                            << last field of derived class 2
 - public 'derived3_o_0' 'Ljava/lang/Object;' @36 
 - public 'derived3_I_0' 'I' @40                                             << last field of derived class 3
 - public 'derived4_I_0' 'I' @44 
 - public 'derived4_o_0' 'Ljava/lang/Object;' @48                            << last field of derived class 4
 - public 'o0' 'Ljava/lang/Object;' @52                                      << this class starts here
 - non-static oop maps (3 entries): 16-20 32-36 48-52

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

Commit messages:
 - alternate-order
 - print

Changes: https://git.openjdk.org/jdk/pull/24330/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=24330&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8353273
  Stats: 48 lines in 2 files changed: 43 ins; 0 del; 5 mod
  Patch: https://git.openjdk.org/jdk/pull/24330.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/24330/head:pull/24330

PR: https://git.openjdk.org/jdk/pull/24330


More information about the hotspot-dev mailing list