JDK-8349061 : Unsafe runtime warnings for off-heap memory accesses are unactionable for libraries and too early
  • Type: Bug
  • Component: core-libs
  • Affected Version: 24
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • Submitted: 2025-01-30
  • Updated: 2025-01-31
  • Resolved: 2025-01-30
Related Reports
Causes :  
Description
Since https://openjdk.org/jeps/498 memory-access methods in sun.misc.Unsafe are warned:

```java
import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class MyLibraryWithOffHeap {

    public static void main(String[] args) {
        long pointer = UNSAFE.allocateMemory(8);
        System.out.println("pointer = " + pointer);
        // Imagine some more useful logic with off-heap memory, just keeping the example short here
    }

    private static final Unsafe UNSAFE = getUnsafe();

    @SuppressWarnings("restriction")
    private static Unsafe getUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new Error(e);
        }
    }

}
```
```
$ java MyLibraryWithOffHeap                                       
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
WARNING: sun.misc.Unsafe::allocateMemory has been called by MyLibraryWithOffHeap (file:...)
WARNING: Please consider reporting this to the maintainers of class MyLibraryWithOffHeap
WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release
pointer = 139857021917392
```

For on-heap memory, the replacement VarHandle is available since a long time, JDK 9, so that should be feasible to migrate to.

However, for off-heap memory, the replacement is the Foreign Function & Memory API (JEP 454), which is only available since JDK 22.

This means the Unsafe off-heap access runtime warnings are not actionable for libraries (and every warning should be actionable), most libraries need to run at least on the latest LTS JDK, that is JDK 21, which doesn't have the Foreign Function & Memory API.
Hence I think the warning is too soon, it should be JDK 25 at earliest, and maybe even the LTS after 25, to allow libraries to e.g. support 21 & 25 at the same time.

Requiring all these libraries (so many use Unsafe: https://github.com/search?q=sun.misc.Unsafe+language%3AJava+&type=code although that doesn't differentiate on-heap/off-heap) to build an abstraction layer to use either Unsafe or Panama based on the JDK runtime version and use multi-release jars seems unreasonable: that's a lot of effort and complications. It's a lot of wasted time for everyone involved.

Doing nothing is one option, but then all users of the library need to pass --sun-misc-unsafe-memory-access=allow and the warning doesn't even mention that. And it will annoy every user of a library using Unsafe, so probably most Java applications out there.
So one probable effect of this warning is most java application will add --sun-misc-unsafe-memory-access=allow. Is that a desirable outcome?

Another option might be to use jdk.internal.misc.Unsafe instead (obviously not ideal), which requires flags, but since a flag is required to silence these warnings anyway maybe not the worse trade-off?

Using JNI seems a no-go because it would add a huge overhead for each off-heap access and it also produces runtime warnings.

Are there any other solutions that I'm missing?
Comments
> Could you then explain concretely how a Java library which uses the off-heap methods and needs to keep supporting JDK 21 (on tip) should deal with those warnings? If the library's tip is baselined in 21 that means that no use of JDK features that are not available in 21 is done in the tip. If the library's tip is not portable and relies on internal classes that are about to be removed, then the library authors need to deal with this by informing their clients that this version of the library is not portable, and if they wish to continue using the library then they must either upgrade to some future version of the library when it's available or they must remain on an old JDK with all that entails (as that is what being non-portable means). This is one of the costs associated with choosing to use internals. The client users will then acknowledge receiving the message that their application will not work without change on future JDKs by suppressing the warning. Once the library authors have migrated away from Unsafe — say, by using FFM — they will baseline the new tip on JDK 22 or later. I understand that behind this question hides the assumptions that a large portion of users will happily accept the risk of big changes to foundational low-level libraries but not the risk of a JDK update. That is precisely the assumtion that JDK 14 claims makes life unnecessarily difficult for library maintainers and that abandoning it makes life easier. > what do you expect any library to do with these warnings? Transition away from Unsafe as soon as possible and inform their users about the status of their current versions as described above. If anything is unclear — either about JEP 471/498 or JEP 14 — please contact me privately as this issue is closed, and so the discussion shouldn't continue here.
31-01-2025

I wrote the previous reply precisely because I felt my feedback has not been addressed and I have seen no concrete solution mentioned in your replies (well, except multi-release jars). > We're confident that the advice in JDK 24 is not only realistic, but easier to implement in practice than all alternatives. Could you then explain concretely how a Java library which uses the off-heap methods and needs to keep supporting JDK 21 (on tip) should deal with those warnings? So far the only solution (besides ignoring 24 entirely) seems to be an abstraction layer to use either Unsafe or Panama based on the JDK runtime version with multi-release jars, which seems a big complication if the library doesn't already have those. I don't see how warnings in 24 instead of 25 has any benefit, what do you expect any library to do with these warnings? I guess most existing applications won't notice because they won't test or try 24 though, so for them it probably matters less.
31-01-2025

Unsafe and other internal classes have, for a couple of decades, come with the privisio that their use is non-portable and that they are subject to removal or change at any point and without any notice. All libraries using these classes have accepted that any benefit of using them comes with a risk for added maintenance. It is precisely because we have recognised that Unsafe is widely used that we have gone above and beyond the agreed terms of use and are informing anyone who may be affected about the change, giving them as much time as possible to prepare. It would be irresponsible to delay communicating the change. Communicating this vital information is done using the same mechanism we've used to communicate other vital information for some years now. Whether or not some people might find information that is crucial for the continued operation of their programs to be annoying, since Java is used for a lot of important software, not receiving that information in time would be more annoying and may result in more severe consequences than a warning on the console. This issue was closed after deliberation and conclusion that all of the points you've raised have been adequately addressed. We're confident that the advice in JDK 14 is not only realistic, but easier to implement in practice than all alternatives. If you find it difficult to implement, you may contact me privately for further assistance.
31-01-2025

I was hoping for a practical solution or workaround in your reply, but I don't see any. I will reply to your individual points then. TLDR: moving the warning to a LTS (25) (or later) would avoid a lot of pain and as far as I can see have no downside. > Everything brought up here is covered in the JEP: https://openjdk.org/jeps/471 I have read the entire JEP. It does not address this issue. It says: > Issue a warning at run time, as detailed below, when a memory-access method is used, whether directly or via reflection. This will alert application developers and users to the forthcoming removal of the methods, and the need to upgrade libraries. But what can applications do about this? Nothing, since the library cannot migrate yet, if the library uses Unsafe off-heap methods (the premise of this issue). (maybe application devs can report an issue to the library, but the library can't do anything about it) So it just warns and annoys both applications and libraries in 24 for (as far as I can see) no reason there. Once both ignore the warning with --sun-misc-unsafe-memory-access=allow (because these warnings are annoying or cause CI failures) it's unlikely they will remember to do something about it later, when it becomes possible to migrate. Well, I guess they will notice when `=allow` becomes disallowed (phase 3, in JDK 26 or later), but then they have no time to fix it, it's already broken at that point. So I guess the idea is all library developers will put themselves a self-reminder when JDK 25 comes out to address that issue? That sounds unlikely to work well in reality. Have I missed something here? How do you think this will play out in practice? Therefore I believe the first warning should be when it is actionable (25), not before. The core principle of a warning is it must be actionable, I hope we can agree with that. Here it is not actionable for Unsafe off-heap method usages in any Java library which supports the latest LTS. Waiting for 25 is just one release later, and then it would be actionable for libraries supporting (only) the latest JDK. The JEP even mentions "Phase 2, issuing run-time warnings, in or before JDK 25;". I'll reply to the rest too, even though I'm pretty sure we'll just disagree there. Focusing on the above seems best, since this is what this issue is about, not a JEP with a discussion on library release models. > It is actionable through https://openjdk.org/jeps/14 I read that. It seems close to common release models, however there are problems which makes it unrealistic, especially in the "Picking a JDK baseline" section: * My understanding is Java users and developers consider non-LTS releases as basically release candidates. Since they only get support for 6 months and no margin to upgrade they are not so different from dev builds, just more stable and last a bit longer, but still so short that most libraries would never consider requiring it, or most applications would never consider running on it. * Therefore it seems unrealistic for a library to have its tip train require a non-LTS JDK (do you know any popular Java library doing that?). And this is the point of this issue: even with a tip/tail model those off-heap memory access warnings cannot be addressed by a library on the tip train, because that would require at most 21, never anything newer (until the next LTS 25 comes out). * If an application is using the tip train, and then wants to stabilize/not constantly update the JDK (because the tip requires it often) they will have to migrate from tip to a tail, this could be very difficult if the closest tail is not so close and they are using library features which are in no tail. If there is a tail (using a LTS JDK) for every bump of the JDK baseline that's no problem (they can keep using tip until the next baseline bump), but that's another reason why a library would only ever use LTS JDKs, even on the tip train. I suppose though one option is that libraries (& applications) might just never test or explicitly not support non-LTS JDKs like 24. But at least some libraries do test multiple JDKs per release train, and would expect that to work well on tip (and maybe tail) trains which have a baseline of the latest LTS. These warnings break that. And warnings can cause CI failures, break command-line application output, etc. `--sun-misc-unsafe-memory-access=allow` is not recognized by JDK 21, so cannot just be set to silence the warnings either. > A non-portable library, by definition, is one that may require different versions of it to be selected depending on the runtime version that the application selects, and every non-portable library has already agreed to these terms. I guess by non-portable library you mean a library using Unsafe. I don't see how. Unsafe from when it was introduced until 21 was AFAIK the only way to efficiently access off-heap memory. Libraries using it never agreed to any terms or required different library versions for different JDK versions, in fact they worked fine so far with almost no changes. (they got spammed by "internal proprietary API" warnings, but those can be suppressed, at least until 22) It's OK to deprecate Unsafe and understandable to want to remove it, but it should be done in a way to make the migration as easy as possible and have minimal pain along the way (I expected that to be lessons learned from the attempt to remove Unsafe in 9). These warnings being added too early cause more pain and potentially delay the migration (since nothing can be done when they are first seen). > The authors of any application that suppresses the warning have, by definition, been made aware that their application will break unless their libraries are replaced or fixed to be portable. That is the purpose of the JEP, so yes, to have every affected user informed is the desirable outcome. I cannot follow: annoying users and breaking (with warnings in 24 or with exceptions later) their applications/libraries is desirable? I already established above they both have no choice but to use this flag to suppress the potentially-breaking warnings if they run on JDK 24 (or let themselves be spammed every time by unactionable warnings, not a good practice, that's just learning to ignore all warnings always then). I guess they can ignore 24, but then this is directly hurting 24 adoption/testing and making it harder for other migrations to be tested in time.
31-01-2025

If you want to propose just changing the warning text, please do so in a separate issue.
30-01-2025

Everything brought up here is covered in the JEP: https://openjdk.org/jeps/471 The purpose of the warning is to inform users that they're making use of a non-portable library, and unless that library is changed or replaced, their program will not work on upcoming versions of the JDK. Once the decision to remove Unsafe has been made, it's in everyone's interest to be made aware of the impact on them as soon as possible. If the warning is postponed, people will have less time to fix or replace their libraries and/or make other decisions regarding the choice of JDK version, and will rightly complain that we've not notified them in time. > This means the Unsafe off-heap access runtime warnings are not actionable for libraries … [because] most libraries need to run at least on the latest LTS JDK, that is JDK 21, which doesn't have the Foreign Function & Memory API. It is actionable through https://openjdk.org/jeps/14 (or https://openjdk.org/jeps/238). There will be no warning when a program using the old version of the library is run on JDK 21. The new version of the library targeting JDK 22 and up and making use of FFM will, similarly, not cause a warning on any 22+ JDK. Applications are free to choose between the old and the new library versions, depending on the runtime version that they select for themselves. A non-portable library, by definition, is one that may require different versions of it to be selected depending on the runtime version that the application selects, and every non-portable library has already agreed to these terms. > So one probable effect of this warning is most java application will add --sun-misc-unsafe-memory-access=allow. Is that a desirable outcome? The authors of any application that suppresses the warning have, by definition, been made aware that their application will break unless their libraries are replaced or fixed to be portable. That is the purpose of the JEP, so yes, to have every affected user informed is the desirable outcome. Note that, unlike with the FFM/JNI warning, there is no "risk approved" option here. Every program that relies on Unsafe — whether or not it disables the warning — will break with 100% certainty on upcoming JDK versions once Unsafe is removed. It's not as if programs can continue running indefinitely with the allow flag and ignore the warning forever. In fact, as JEP 471 explains, the allow flag will stop working even before Unsafe is removed. It is intended as a temporary measure and it can only function temporarily.
30-01-2025