【发布时间】:2018-11-29 16:03:42
【问题描述】:
在 OpenJDK 8 中,可以访问 sun.misc.VM 并调用 isDirectMemoryPageAligned 和 maxDirectMemory。isDirectMemoryPageAligned 用于正确分配要分配的直接内存大小,正如 DirectByteBuffer 所做的那样。maxDirectMemory 用于报告内存统计信息以及访问为-XX:MaxDirectMemorySize 配置的值。在内部,它会对直接内存的允许消耗设置一个限制。
自 OpenJDK 9 起,类 VM 已移至 jdk.internal.misc,除非在运行应用程序时使用 --add-export java.base/jdk.internal.misc=xyz,否则该类 VM 不可用。
有没有“正确”的方法来做到这一点?
我已经尝试使用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。 :(
【问题讨论】:
-
你测试过@VGR 吗?如果是这样,请向我报告您使用的虚拟机。我会试着找出原因。这里的技巧是使用
--add-exports的动态等效项打开包,这是使用 java.lang.Module 和反射的私有方法完成的。见this code -
问题中包含的 hack 非常可怕,随时可能中断。多个版本的直接缓冲区都没有进行页面对齐,因此不清楚为什么现在需要这样做。更多关于 -XX:MaxDirectMemorySize= 值的信息也需要。
-
自 JDK 6 以来,缓冲区没有进行页面对齐。没有支持的接口可用于您正在做的事情,最好先解释一下为什么需要它?
-
为什么不直接调用 ByteBuffer.allocateDirect 呢?
-
如果您自己分配内存,那么您可以使用 JNI 的 NewDirectByteBuffer 将该区域包装为直接缓冲区,也许这就是您要寻找的。span>