【问题标题】:How to run code on jre9 that was compiled with jdk8 and use Unsafe如何在使用 jdk8 编译的 jre9 上运行代码并使用 Unsafe
【发布时间】:2018-03-27 13:19:08
【问题描述】:

我有使用 jdk8 作为 java 1.8 的目标和源编译的代码,并使用 Unsafe。我尝试使用 jdk9 运行该程序,但失败并出现以下异常:

java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte

包 sun.misc.Unsafe 没有从 jdk9 中删除,所以我希望代码能够运行。我不能用jdk9重新编译代码,我希望java应该是向后兼容的。

我创建了一个不适合我的小测试。 测试类:

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class Test {

  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    System.out.println("before");
    Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
    theUnsafeField.setAccessible(true);

    Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
    unsafe.getByte(new Object(), 4);
    System.out.println("after");
  }
}

然后我用jdk8编译代码。

C:\Java-IDE\jdk1.8.0_121\bin\javac.exe Test.java

如果我用 jdk8 运行它,它可以工作:

C:\Java-IDE\jdk1.8.0_121\bin\java.exe Test
before
after

如果我用 jdk9 运行它会抛出异常:

C:\Java-IDE\jdk-9.0.4_windows-x64_bin\bin\java.exe Test
before
Exception in thread "main" java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte(Ljava/lang/Object;I)B
        at Test.main(Test.java:13)

相信在jdk9下也应该可以运行。有可能吗?

【问题讨论】:

  • 您可能只需要添加 jdk.unsupported 模块 - 在命令行上尝试 --add-modules=jdk.unsupported 或更新项目的模块信息(如果有的话)。
  • 是的,我正在运行 --add-modules=jdk.unsupported 但它仍然抛出异常
  • 这里有点可疑。该方法在 JDK 9 和 JDK 10 中仍然存在。请告诉我们更多关于您是如何运行它的?
  • 我看到了问题,getByte(Object,int) 已被删除。将 4 转换为 (long)4 以便使用 getByte(Object,long) 方法。
  • 对了,你需要重新编译代码(使用JDK 8)才能使用getByte(Object,long)。然后它将在 JDK 8 和 JDK 9 上运行。

标签: java-9 backwards-compatibility unsafe


【解决方案1】:

byte Unsafe.getByte(Object, int) 方法已在 Java 9 中删除,但重新编译解决了这个问题,因为它会导致调用 byte Unsafe.getByte(Object, long),这确实是预期的替换。

请注意,即使 Unsafe 是一个非官方的、不受支持的 API 不应被应用程序使用,使用 int 偏移量的方法也已被弃用,而支持使用 long 的方法,因为 1.4.1,意味着有十年半的时间来适应旧代码,但是您说代码“以jdk8为目标编译”表明它实际上比这更年轻。

鉴于已多次宣布计划完全删除sun.misc.Unsafe,因此如果要在未来的 JVM 版本上运行,将无法更改代码。如果你不能重新编译它,问问自己,你不能重新编译的代码的未来维护应该是什么样子。如果代码应该被冻结,那么也冻结 JVM 版本。否则,你需要想办法重新编译或替换它。

【讨论】:

    【解决方案2】:

    是的,java 是向后兼容的,但它是针对 java API 的。 软件包 sun.misc 是 Sun/Oracle 在没有任何事先警告的情况下宣传为可移动/可更新/可删除的软件包之一。

    原来如此

    要回答您的问题,您需要更新您的代码

    编辑:

    就像 Alan Bateman 在他的评论中所说,显而易见的解决方案是重新编译

    但如果你不能,并且如果你不反对丑陋的黑客,你可以:

    1. 获取 sun.misc.Unsafe 的来源并插入您需要/缺少的方法

    2. 创建一个自定义类加载器,它基本上与系统类加载器执行相同的操作,但是当请求加载 sun.misc.Unsafe 时,将加载您的 Unsafe 版本

    3. 使用您的自定义类加载器启动您的应用程序

      java -Djava.system.class.loader=com.xxx.MyCustomClassLoader xxx

    丑陋但无需重新编译也可以工作

    【讨论】:

    • 它没有被删除openjdk.java.net/jeps/260。我无法重新编译代码。在 jdk9 下也应该可以使用 unsafe。
    • 它没有被删除 - 它仍然存在,但在 jdk.unsupported 模块中
    • 似乎“不安全”已通过删除 getByte 方法“更新”
    • No 方法 getByte 没有被移除。
    • 好吧,无论是现在还是将来,以上只是恕我直言的评论。对低质量投反对票。
    猜你喜欢
    • 2022-01-18
    • 1970-01-01
    • 2014-05-01
    • 2019-06-24
    • 1970-01-01
    • 2018-08-21
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多