当前位置: 首页 > 面试题库 >

强制JVM在没有页面缓存的情况下执行所有IO(例如O_DIRECT)

魏波娃
2023-03-14
问题内容

我正在做一些用Java编写的应用程序的基准测试。对于实验而言,非常重要的一点是结果不受页面缓存的影响(我使用的是Linux)

因此,避免打开页面缓存的最佳方法是在每次打开文件时使用O_DIRECT。因此,我在jre的源代码中更改了相应的代码

我的方法对于经历FileOutputStream(例如写作)的所有事物都非常适用,但是对FileInputStream(例如阅读)却不起作用。

将O_DIRECT添加到的open-call中时FileInputStream,JVM无法加载任何类:

Error: Could not find or load main class perf.TestDirectIO

该错误不是类路径问题,因为我可以通过使用“未破解”的JVM来解决它。

因此,打开文件似乎存在问题。

对于如何解决此问题的任何建议,我感到非常高兴。

如果有人想做类似的事情,我已经在我的博客中记录了整个黑客事件。

作为参考,这些是我在JVM代码上所做的更改:

jdk/src/share/native/java/io/FileInputStream.c

 @@ -58,7 +60,8 @@
 JNIEXPORT void JNICALL
 Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) {
-    fileOpen(env, this, path, fis_fd, O_RDONLY);
+    fileOpen(env, this, path, fis_fd, O_RDONLY | O_DIRECT); // this is the change that causes all the problems
 }

此更改有效 jdk/src/solaris/native/java/io/FileOutputStream_md.c

@@ -55,8 +55,10 @@
 JNIEXPORT void JNICALL
 Java_java_io_FileOutputStream_open(JNIEnv *env, jobject this,
                                    jstring path, jboolean append) {
     fileOpen(env, this, path, fos_fd,
-             O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC));
+             O_WRONLY | O_DIRECT | O_CREAT | (append ? O_APPEND : O_TRUNC));
 }

我还更改了热点jre以确保对齐内存(这是O_DIRECT的要求) hotspot/src/share/vm/runtime/os.cpp

+# include <mm_malloc.h>
...
-  u_char* ptr = (u_char*)::malloc(size + space_before + space_after);
+  u_char* ptr = (u_char*)::_mm_malloc(size + space_before + space_after,512);

问题答案:
  "The thing that has always disturbed me about O_DIRECT is that the
   whole interface is just stupid, and was probably designed by a

deranged
monkey on some serious mind-controlling substances [*].”

[*]换句话说,这是一种Oracle主义。

- 来自Transmeta的Linus
Torvalds,2002年5月11日

检查以下内容的“注意”部分man 2 open

O_DIRECT

O_DIRECT标志可能对 用户空间缓冲区 的长度和地址 以及I / O 的 文件偏移量 施加对齐 限制
。在Linux中,对齐限制因文件系统和内核版本而异。

在Linux 2.4下,传输大小以及用户缓冲区和文件偏移的对齐方式都必须是文件系统逻辑块大小的倍数。在Linux
2.6下,对齐到512字节边界就足够了。....

总之,O_DIRECT是潜在强大的工具,应谨慎使用。建议应用程序将O_DIRECT的使用作为性能选项,默认情况下禁用。

我认为,JRE(类加载器)在FileInputStream中有一些用法,其读取的偏移量或大小未对齐512字节。(对于高级格式,最小对齐方式可能更大,甚至是4096字节或一页4K。)

内核未对齐偏移的行为是灰色区域,一些信息在这里:RFC:澄清直接I / O语义,Theodore Ts’o,tytso @
mit,LWN,2009年

其他有趣的讨论在这里:Linux:使用O_DIRECT访问文件(内核陷阱,2007年)

嗯,当DIRECT发生故障时,似乎应该回退到缓冲的I /
O。使用DIRECT的所有IO操作都是同步的。可能是某些DMA效果?或O_DIRECT和的组合mmap

更新:

感谢strace输出。这是错误(grep O_DIRECT,然后检查文件描述符操作):

28290 open("...pact/perf/TestDirectIO.class", O_RDONLY|O_DIRECT) = 11
28290 fstat(11, {st_mode=S_IFREG|0644, st_size=2340, ...}) = 0
28290 fcntl(11, F_GETFD)                = 0
28290 fcntl(11, F_SETFD, FD_CLOEXEC)    = 0
...skip
28290 stat("...pact/perf/TestDirectIO.class", {st_mode=S_IFREG|0644, st_size=2340, ...}) = 0
...skip
28290 read(11, "\312\376\272\276\0\0\0003\0\215\n\0-\0D\t\0E\0F\7\0G\n\0\3\0D\10\0H\n"..., 1024) = 1024
28290 read(11, 0x7f1d76d23a00, 1316)    = -1 EINVAL (Invalid argument)

未对齐的读取大小会导致EINVAL错误。您的类文件长2340字节,它是1024 + 1316字节,未对齐。



 类似资料:
  • 我正在制作应用程序与视频播放器在它和我的整个结构是为只有肖像视图,除了这个视频播放器。我只想为这个视图启用景观旋转。但是我在很多论坛上做了很多文章,每一篇文章都是为了给App Delegate添加一些代码,但是我没有。那我能做什么。

  • 问题内容: 我正在寻找没有浏览器的Javascript编程。我想从Linux或MacOSX命令行运行脚本,就像我们运行任何其他脚本语言(ruby,PHP,Perl,Python …)一样 我研究了spider monkey(Mozilla)和v8(Google),但它们似乎都是嵌入式的。 是否有人将Javascript作为脚本语言从命令行执行? 如果有人好奇,为什么我期待到这一点,我一直在关注着N

  • 问题内容: 我想在Centos7上使用shell脚本自动生成一对ssh密钥,我已经尝试过 所有这些命令都不起作用,仅输入一个“ enter”,然后在“ Enter passphrase(空无密码)为空”时停止shell脚本,我只想知道如何在shell中连续模拟多个“ enter”。 非常感谢任何人的帮助! 问题答案: 只需 使用一个空白通 使用标志: 要覆盖密钥文件 (在此示例中): 从 手册 页

  • 问题内容: 我有一种方法可以做很多事情。其中包括进行大量插入和更新。因此宣布… 它的工作完全符合预期,我对此没有任何问题。但是在某些情况下,尽管没有异常,但我还是想强制回滚…目前,当我遇到合适的条件时,我正在强制异常,但这很丑陋,我不喜欢它。 我可以以某种方式积极地调用回滚吗?异常调用它…我在想也许我也可以。 问题答案: 在Spring Transactions中,您使用。 您在这里遇到的问题是您

  • 问题内容: 我想知道在不提示输入密码的情况下执行数据库mysqldump的命令。 原因:我想运行一个cron作业,该作业每天执行一次mysqldump数据库的转储。因此,出现提示时,我将无法插入密码。 我该如何解决? 问题答案: 由于您正在使用Ubuntu,因此您所要做的只是在主目录中添加一个文件,这将禁用mysqldump密码提示。这是通过创建文件来完成的(权限需要为600)。 将此添加到.my

  • 问题内容: 我有一个没有情节提要的应用程序,所有UI创建都是通过代码完成的,我得到了一个我可以使其在iPhone上使用的应用程序,因为该应用程序最初仅是为iPad设计的,因此当您在列表中选择一行时,大师认为,它在iPhone上什么也不做,但在iPad上工作正常。 所以我的问题是我可以创建并执行允许在方法上显示“详细视图”的segue 吗? 到目前为止,这是我所做的: 但是当运行并选择一行时,应用程