将 sun.misc.VM 的访问权限替换为 JDK 11

Replace access to sun.misc.VM for JDK 11

在 OpenJDK 8 中,可以访问 sun.misc.VM 并调用 isDirectMemoryPageAlignedmaxDirectMemory
isDirectMemoryPageAligned 用于正确调整要分配的直接内存的大小,如 DirectByteBuffer 所做的那样。
maxDirectMemory 用于报告内存统计信息以及为 -XX:MaxDirectMemorySize 配置的值的访问。在内部,它将对允许的直接内存消耗设置限制。

自 OpenJDK 9 起,class VM 已移至 jdk.internal.misc,除非在 运行 应用程序。

有没有 "right" 方法来做到这一点?

我已经尝试使用 ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage().getMax() 替代 maxDirectMemory 但它总是返回 -1 - 意味着该值不可用。也可以通过反射访问 java.nio.Bits#MAX_MEMORY,但它仍然是“hackish”。


请注意,可能非常非常脏并执行以下操作 - 适用于 OpenJDK、Zulu 和 Oracle 11.0.1 - 但这不是此问题的目标。

public static void tryExportInternal() {
    final String moduleName = "jdk.internal.misc";
    final Module javaLang = Integer.class.getModule();

    // Method used only for tests by the JDK...
    final Method exporter;
    try {
        exporter = Module.class.getDeclaredMethod("implAddExports", String.class);
        exporter.setAccessible(true);
        exporter.invoke(javaLang, moduleName);
    } catch (NoSuchMethodException | IllegalAccessException e) {
        LOG.log(Level.INFO, "Cannot access internal Module method", e);
    } catch (InvocationTargetException e) {
        LOG.log(Level.INFO, "Cannot call internal Module method", e);
    }
}

在源代码中,implAddExports被标记为@apiNote This method is for JDK tests only :(

此答案来自Alan Bateman对问题的各种评论。

不,没有标准API来访问这两个想要的方法。

自 JDK6 起,DirectxxxBuffers 不再进行分页对齐。因此,不需要访问 VM.isDirectMemoryPageAligned 来重现 DirectBuffers 的功能。


关于手动内存分配,作为问题背后的用例,目前唯一 API 进行直接内存分配的是 ByteBuffer.allocateDirect,或其 JNI 替代方案 NewDirectByteBuffer


评论参考: