如何通过使用映射到空页更换,以取消映射mmap'd文件

问题描述 投票:1回答:2

是否有在Linux用户空间的方式来替换映射文件(一定逻辑地址范围内或mmap'd页)与空页(从/dev/null,或者一个空单页映射页,超过的顶部反复映射从文件页面映射)?

对于情况下,我想找到这个JDK错误修复:

https://bugs.openjdk.java.net/browse/JDK-4724038

总结错误:它是目前不可能取消映射在Java文件,直到JVM可以收集垃圾的一个包装mmap'd文件,因为强行解除映射文件可能会引起由于竞争条件安全问题MappedByteBuffer(如本地代码仍然可以尝试访问该文件被映射到相同的地址范围,并且操作系统可能已经映射了一个新的文件到相同逻辑地址范围)。

我期待,以取代在逻辑地址范围映射的页面,然后取消映射文件。有没有办法做到这一点?

(奖励积分,如果你知道在其他操作系统这样的方式也一样,特别是Windows和Mac OS X.)

请注意,这并不一定是一个原子操作。其主要目标是将内存的取消映射(或映射文件内容与零上阅读的页面替换)从文件的收盘分开,因为这将解决的问题在Linux一连串的(其中有一个下限对每个进程文件描述符)和Windows(事实上虽然它被映射,你不能删除文件)的数量。

UPDATE:又见:Memory-mapping a file in Windows with SHARE attribute (so file is not locked against deletion)

linux memory-management mmap virtual-memory
2个回答
1
投票

在Linux上,你可以使用mmapMAP_FIXED你想要的任何映射替换的映射。如果更换整个映射的参考文件将被删除。


1
投票

错误保留在JDK,只要是从根本上是因为争用条件在解除映射存储器和映射所述虚拟存储器之间的原因,一些其它存储器可能最终映射有(潜在地由本机代码)。我一直在OS API和存在没有在系统调用级别原子存储器操作即取消映射文件映射到同一地址的东西。但是有一些阻碍的全过程,同时从它的下面换出的地图解决方案。

去映射正常工作中的finalize没有保护,因为GC已经证明对象是不可达的第一,所以没有比赛。

高度Linux的具体的解决方案:

1)的vfork()

2)发送父STOP信号

3)取消映射的存储器

4)在它的位置映射零

5)发送父CONT信号

6)_exit(其放开父线程)

在Linux中,内存映射更改传播到父。

该代码实际上看起来更像这个(vfork()是疯狂的人):

int unmap(void *addr, int length)
{
    int wstatus;
    pid_t child;
    pid_t parent;
    int thread_cancel_state;
    signal_set signal_set;
    signal_set old_signal_set;

    parent = getpid();
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &thread_cancel_state);
    sigfillset(&signal_set);
    pthread_sigmask(SIG_SETMASK, &signal_set, &old_signal_set);
    if (0 == (child = vfork()) {
        int err = 0;
        kill(parent, SIGSTOP);
        if (-1 == munmap(addr, length))
            err = 1;
        else if ((void*)-1 == mmap(addr, length, PROT_NONE, MAP_ANONYMOUS, -1, 0);
            err = 1;
        kill(parent, SIGCONT);
        _exit(err);
    }
    if (child > 0)
        waitpid(child, &wstatus, 0);
    else
        wstatus = 255;

    pthread_sigmask(SIG_SETMASK, &old_signal_set, &signal_set);
    pthread_setcancelstate(thread_cancel_state, &thread_cancel_state);
    return (wstatus & 255) != 0;
}

在Windows下,你可以做停止所有线程,但是这一次使用SuspendThread这感觉这个量身定做的。然而,枚举线程会因为你争分夺秒CreateThread很难。你必须运行枚举线程ntdll.dll的API(你不能使用TOOLHELP这里相信我),并SuspendThread每个人,但你自己的,仔细只用VirtualAlloc函数的内存,因为SuspendThread刚刚打破所有的堆分配程序,并且你将有做一切在一个循环,直到你找到没了。

这里也有一些书面记录在这里,我不太觉得我能准确地提炼了下来:

http://forums.codeguru.com/showthread.php?200588-How-to-enumerate-threads-in-currently-running-process

我没有找到Mac OSX上的任何解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.