【发布时间】:2019-01-23 23:55:27
【问题描述】:
Linux用户空间有没有办法用空页面(从/dev/null映射,或者可能是一个空页面,重复映射)替换映射文件的页面(或某个逻辑地址范围内的mmap页面)在从文件映射的页面的顶部)?
就上下文而言,我想找到一个解决这个 JDK 错误的方法:
https://bugs.openjdk.java.net/browse/JDK-4724038
总结这个错误:在 JVM 可以垃圾收集包装 mmap 文件的 MappedByteBuffer 之前,目前无法在 Java 中取消映射文件,因为强制取消映射文件可能会因竞争而导致安全问题条件(例如,本机代码可能仍在尝试访问文件映射到的相同地址范围,并且操作系统可能已经将新文件映射到相同的逻辑地址范围)。
我正在寻找替换逻辑地址范围内的映射页面,然后取消映射文件。有没有办法做到这一点?
(如果您也知道在其他操作系统(尤其是 Windows 和 Mac OS X)中执行此操作的方法,则可以加分。)
请注意,这不一定是原子操作。主要目标是将内存的取消映射(或用读取时为零的页面替换映射的文件内容)与文件的关闭分开,因为这将解决 Linux (具有每个进程的文件描述符数量的下限)和 Windows(事实上您不能在映射文件时删除文件)。
更新:另见:Memory-mapping a file in Windows with SHARE attribute (so file is not locked against deletion)
【问题讨论】:
-
以原子方式写入多个内存位置的唯一方法是在使用该内存的所有线程之间使用互斥锁。如果线程没有遵循协议来调解对内存的访问,那么你就不走运了。
-
@Barmar:这不是有问题的竞争条件,它是取消映射文件和线程停止使用文件映射到的地址空间之间的竞争条件。我的建议是插入一个中间步骤,将地址空间中的所有页面重新映射到占位符空页面(不必原子地发生)或 /dev/null 或类似的,然后取消映射文件,以便关闭文件和释放地址空间可以分两个单独的步骤完成。这将解决链接错误报告中的问题。
-
那个 JDK bug 中描述的问题是因为 Java 代码没有直接访问内存映射系统调用的权限,而
munmap在 GC 注意到对象被释放时会延迟发生。如果您直接对 Linux 系统调用进行编码,则在调用munmap()时没有竞争条件。 -
当然,您必须在使用它的所有线程之间协调对该映射内存的访问。这不是竞争条件,这只是应用程序设计的问题。为什么你甚至想在所有线程完成之前取消映射文件?而且如果他们不这样做,用空页面替换映射很可能会导致他们出错。
-
@Barmar,你误解了这个问题。请参阅链接的 JDK 错误报告。这是关于修复 JDK API(这需要修复潜在的安全漏洞),而不是应用程序错误。
标签: linux memory-management mmap virtual-memory