JDK-8350272 : Deprecate UseCompressedClassPointers for removal
  • Type: JEP
  • Component: hotspot
  • Sub-Component: runtime
  • Priority: P4
  • Status: Closed
  • Resolution: Withdrawn
  • Submitted: 2025-02-18
  • Updated: 2025-02-27
  • Resolved: 2025-02-27
Related Reports
Duplicate :  
Relates :  
Description
Summary
-------

Deprecate the flag `UseCompressedClassPointers`, with the intent to remove the flag and implementation of uncompressed class-pointers in a future release.

Motivation
----------

Shortly after the adoption of 64-bit architectures the `-XX:[-|+]UseCompressedClassPointers` and `-XX:[-|+]UseCompressedOops` arguments were added to provide Java users the ability to enable using 32-bit references even when on a 64-bit architecture. This reduces memory overhead and help reduce cache misses. Originally, the two flags were coupled, which meant that +UseCompressedClassPointers depended on +UseCompressedOops. Starting in JDK 15, the two options have been decoupled, which means that +UseCompressedClassPointers can be used indepent from +UseCompressedOops. This greatly reduced the need for -UseCompressedClassPointers. JDK-8332514 extended the addressable class-space of compressed classes to 4GB and JDK-8338526 moved interface and abstract classes out of class-space, both of which further reduce the need for `-UseCompressedClassPointers`.

On the other hand, maintaining the code to support uncompressed class-pointers is an on-going cost, and having alternative code-paths in performance-critical code such as the accessor for loading the Klass* out of an object has shown to impact performance in some situations. In the long run, the HotSpot JVM should settle on a single object header layout.

Deprecating the flag `UseCompressedClassPointers` will allow us to remove the flag in a future release, and thus reduce maintenance burden, improve performance and pave the way for a single object header layout.

Description
-----------

An attempt to run with [+/-]UseCompressedClassPointers will produce:

WARNING: The flag UseCompressedClassPointers is deprecated and may be removed in a future release.


Alternatives
------------

TBD: maybe describe near-/far-Klass approach.

Risks and Assumptions
---------------------

There is a risk that an application might need more than 4GB of class-space (roughly 4 million addressable classes with +UseCompactObjectHeaders, 5-6 million classes with -UseCompactObjectHeaders). Realistically, this can only be achieved by generating a lot of classes. JDK-8338526 reduces that risk by avoiding to place interface and abstract classes into class-space to begin with - many generated classes are all-static classes and can be treated as abstract classes.

If there is a pressing need to support more than 4 million classes / 4GB of class-space, we can implement near/far-Klasses proposal, which would support addressing virtually unlimited number of classes using compressed class-pointers. However, this would likely come at a cost, and should therefore only be considered if really necessary.

Dependencies
------------

The 32 bit JVMs currently use uncompressed class-pointers. Before `UseCompressedClassPointers` can be obsoleted in a future release, the 32 bit JVMs need to be changed to use compressed class-pointers (which would mean a kind of fake compressed class-pointers, because there is no need to compress anything).
Comments
I'm withdrawing this in favor of JDK-8350754.
27-02-2025

CSR: https://bugs.openjdk.org/browse/JDK-8350754
27-02-2025

Ok, so let's file a new CSR instead, and then discard this JEP proposal.
25-02-2025

[~stuefe] thank you for answering my question. This should be in description.
25-02-2025

I don't think we should keep the flag in any form - corresponding code will be removed anyway.
25-02-2025

[~rkennke] Here is wiki explaining lifecycle for VM flags: https://wiki.openjdk.org/display/HotSpot/Hotspot+Command-line+Flags%3A+Kinds%2C+Lifecycle+and+the+CSR+Process
25-02-2025

I am also fine with converting this into CSR. To be clear, I am fine with deprecating this flag.
25-02-2025

I'm ok with converting this to a CSR, if you are all ok with it. I was not sure if a JEP would be warranted. I am also not sure if we can and should deprecate only -UCCP but not +UCCP. Deprecating and even obsoleting the flag means that the flag would still be accepted (with a warning), obsoletion would remove the -UCCP path, but still accept and ignore the flag. I think we should deprecate the whole flag by the usual process, and we might decide to never expire it (?).
25-02-2025

Please see the preceding discussion on this topic: https://mail.openjdk.org/pipermail/hotspot-dev/2025-February/101023.html My current thoughts are this: There is a low but non-zero risk, but we should do it nevertheless. Besides the reduction in maintenance efforts, I believe this flag is usually applied for the wrong reasons, based on misunderstandings. I would prefer doing this as a CSR, though. I dislike the red tape associated with JEPs and think the "we reach more people" idea may be overly optimistic. Maybe not, but in my experience nobody cares until they stumble over it. Most uses of `UseCompressedClassPointers` are probably hidden in configuration files. About that, I scanned GitHub for uses of this flag. Uses of `-UseCompressedClassPointers` are somewhat sparse. I get ~700 hits, many repeats when forks are involved, excluding the OpenJDK itself. Where the reasons are clear, they seem to group into the following: - Uses of `-UseCompressedClassPointers` for short-lived java processes. There seems to be a widespread belief that "+UseCompressedClassSpace uses too much memory upfront" so it gets avoided. This seems to be a misunderstanding of what vsize is vs. RSS. Ironically, avoiding this option then uses more heap memory, so the net footprint is larger. I believe that is a reason why removing `-UseCompressedClassPointers` can be beneficial long term. For an example of a well-written and completely wrong comment see [2] - Many uses in documentation and notes people wrote for themselves - Some uses mention "we have to do this otherwise the JVM crashes" - not a good reason, if there are crashes, they should be fixed. - Some uses specifically target arm64. I believe this is because the arm64 class space reservation is troublesome and has historically been a bit buggy. Unlike other implementations, we have no "allocate-anywhere" fallback path there - the class space has to be reserved in a particularly aligned way to work. This usually works since the pool of valid addresses to choose from is very large, but it could be the reason for uses like this [3], where someone claims that class space reservation fails on iOS. I think this can be easily fixed, though, we just have to do that (e.g. at the cost of an additional load, load the encoding base from memory). ----- I get many more hits for +UseCompressedClassPointers (~4k). Therefore I propose to not deprecate the full UseCompressedClassPointers switch for JDK 25, which is an LTS; instead, I propose to just deprecate the use of the switch in its negative form for JDK 25, and leave full deprecation of this switch for JDK 26. ----- About risks: - As was said in the original discussion [1], I think the fear of running out of class space is overblown. To set this in perspective, filling 4GB of class space will net you somewhere between 25 and 45 GB (the typical ratio between class space to non-class metaspace use is 1:6 to 1:10) for total metaspace usage. I think these scenarios are pathological. Nevertheless, we have a mitigation in mind (far classes). - Note that +UseCompressedClassPointers was historically tied to +UseCompressedOops, therefore installations using more than 32GB running on JDK 8 or 11 may implicitly rely (for unknown reasons) on -UseCompressedClassPointers without explicitly stating that in arguments, or without even knowing. Upgrading those to JDK 25 or later could uncover these implicit assumptions. [1] https://mail.openjdk.org/pipermail/hotspot-dev/2025-February/101023.html [2] https://github.com/jobar/ansidoop/blob/9618e31d65089b7586ac1c4f76de5bd748e59c4b/roles/spark-common/templates/spark-defaults.conf.j2#L17 [3] https://github.com/PojavLauncherTeam/PojavLauncher_iOS/blob/7d8203b2578c62b5153fedc67d13aacd567571d3/Natives/JavaLauncher.m#L280-L283
25-02-2025

[~kvn] We already have solutions for that, nothing needs to be added. When Metaspace or class space run out, we generate an OOME. That triggers the `xxxOnOutOfMemoryError` actions like other OOMEs do.
25-02-2025

Thanks for your research, Thomas. I'm fine if this is a CSR to Deprecate the option (positive and negative values, you can't really separate them from the mechanism we use to deprecate options, which prints a deprecation message). I would hope that the option can be Obsoleted in 26 (ie. code removed) though since the purpose of deprecating it is to have fewer object header formats.
25-02-2025

Add in Description what happens if we out of space for classes (crash VM with OOM message as we currently do heap?). As I understand this proposal will not include solutions described in Risk and Assumptions. Will you duplicate flags we have for OOM in heap? Like `-XX:+OnOutOfMemoryError=<cmd>`, `-XX:+HeapDumpOnOutOfMemoryError` etc. Or may be reuse them? Do we already have similar flags and functionality for meatspace?
19-02-2025

For alternatives, you could describe a scheme where there's an extension bit or intermediary dispatch class to the real class if the number of classes exceeds what can be stored in 4GB. But I think a general statement that we could implement some mitigation strategies if the storage for classes ever exceeds 4G within the existing framework, should be sufficient. There have been issues when we've run out of class metaspace, but those were always due to runaway class loading and leakage and not representative of real applications. This JEP could be only a CSR request but the extra visibility of the JEP seems like it's worth the extra process. I think this is a really good thing to do for JDK 25.
19-02-2025