JDK-7133093 : Improve system dictionary performance
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: hs23
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2012-01-25
  • Updated: 2019-05-22
  • Resolved: 2017-07-28
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 10
10 b21Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Improve access time for loaded class cache (system dictionary).

..is it possible that the internal data structure might one day change from monolithic hash table to something more hierarchical?  For example having a separate data structure per package or per classloader.  I was reading online about something called a HAT-trie that deals with shared prefixes and was designed with cache locality in mind.

email from ###@###.###

Comments
I changed the name of the bug back because I checked it in with this name.
01-08-2017

The SystemDictionary is an "AllStatic" class in the Hotspot vm that holds static global variables for data structures related to class loading. These are global in the Hotspot jvm. // Hashtable holding loaded classes. static Dictionary* _dictionary; // Hashtable holding placeholders for classes being loaded. static PlaceholderTable* _placeholders; // Hashtable holding classes from the shared archive. static Dictionary* _shared_dictionary; // Lock object for system class loader static oop _system_loader_lock_obj; // Constraints on class loaders static LoaderConstraintTable* _loader_constraints; // Resolution errors static ResolutionErrorTable* _resolution_errors; // Invoke methods (JSR 292) static SymbolPropertyTable* _invoke_method_table; The type Dictionary is a subclass of Hashtable<Klass*, mtClass>, that is, it's a hash table. What is stored in the Dictionary is the loaded class cache. When a class is loaded, it's entry is added to the global Dictionary with it's class loader: class C, class loader L When a class causes the loading of another class, the vm must search the dictionary to see if D has already been loaded. class C, class loader L => loads class D in class loader M It starts with L, and follows the class loader L's logic (usually delegating to L's parent loaders), until D is found and loaded. D is added to the Dictionary: class D, class loader M The vm then caches that class loader L has loaded D, so that the next lookup doesn't need to search through the class loader delegation to find D was loaded by M. I think there's quite a bit of upcalls and downcalls between Java and the vm, so this caching is profitable for performance. ^class D, class loader L The printing function puts a '^' if the initiating loader is different than the owning class loader, ie D->class_loader_data() == M. So this has breezed by a lot of details! The key point to note is that the Dictionary contains entries (class, class_loader) where class may not be loaded by that class_loader, but whose loading was initiated by that class loader. There is also a pd_set associated with each entry which I'm not going to write up in this. That works the same. The change under discussion is to make one dictionary per ClassLoaderData, and store both loaded and initiated classes for that class loader in each dictionary. In our example here, the ClassLoaderData for L would contain two entries in it's dictionary, one for C and one for D. Lookup through the initiating loader would look through the dictionary for the ClassLoaderData for the initiating loader. ie: Dictionary for class loader class loader 0x00007f8f9c0d4700 a 'runThese$DirectoryClassLoader'{0x00000000c01436c0} Java system dictionary (table_size=107, classes=9) ^ indicates that initiating loader is different from defining loader 11: javasoft.sqe.tests.vm.concepts.exceptions.exceptions033.exceptions03301.TestThread, loader class loader 0x00007f8f9c0d4700 a 'runThese$DirectoryClassLoader'{0x00000000c01436c0} 36: javasoft.sqe.tests.vm.concepts.exceptions.exceptions033.exceptions03301.exceptions03301, loader class loader 0x00007f8f9c0d4700 a 'runThese$DirectoryClassLoader'{0x00000000c01436c0} 64: ^java.lang.Thread, loader NULL class_loader 67: ^java.io.PrintStream, loader NULL class_loader 68: ^java.lang.ThreadGroup, loader NULL class_loader ... Dictionary for class loader NULL class_loader Java system dictionary (table_size=1009, classes=1025) ^ indicates that initiating loader is different from defining loader 0: jdk.internal.loader.URLClassPath$JarLoader, loader NULL class_loader ... The change essentially adds a Dictionary hashtable to each ClassLoaderData: class ClassLoaderData : public CHeap<mtClass> { Dictionary* volatile _dictionary; // The loaded InstanceKlasses, including initiated by this class loader And lookup uses the current class_loader->dictionary() as the dictionary to look up classes. Dictionary* dictionary = loader_data->dictionary(); unsigned int d_hash = dictionary->compute_hash(name, loader_data); int d_index = dictionary->hash_to_index(d_hash); Klass* probe = dictionary->find(d_index, d_hash, name, protection_domain); if (probe != NULL) return probe;
19-06-2017

Also possible that we might search per class loader data rather than a single global system dictionary. Worth prototyping alternatives.
17-07-2013