购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.2.1 多视图映射

前面我们提到MMU负责映射虚拟地址和物理地址,操作系统主要负责维护页表(page table),页表维护了虚拟地址和物理地址的映射关系。实际上现在的系统还支持多个虚拟地址同时映射到一个物理地址上,多个虚拟地址可以认为它们是彼此之间的别名。当我们操作其中一个虚拟地址,例如存储数据时,所有的虚拟地址都应该能访问到最新的数据。

这一特性在某些场景中特别有用,例如可以利用这一特性在两个虚拟地址之间复制大量的数据。这里介绍一下Linux和Windows这两种系统下是如何实现多视图映射的。

1.Linux系统

首先我们通过一个例子演示Linux多视图映射。Linux中主要通过系统函数mmap完成视图映射。多个视图映射就是多次调用mmap函数,多次调用的返回结果就是不同的虚拟地址。示例代码 如下:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdint.h>
int main()
{
    //创建一个共享内存的文件描述符
    int fd = shm_open("/example", O_RDWR | O_CREAT | O_EXCL, 0600);
    if (fd == -1) return 0;
    //防止资源泄露,需要删除。执行之后共享对象仍然存活,但是不能通过名字访问
    shm_unlink("/example"); 
    //将共享内存对象的大小设置为4字节
    size_t size = sizeof(uint32_t);
    ftruncate(fd, size); 
    //两次调用mmap,把一个共享内存对象映射到两个虚拟地址上
    int prot = PROT_READ | PROT_WRITE;    
    uint32_t *add1 = mmap(NULL, size, prot, MAP_SHARED, fd, 0);
    uint32_t *add2 = mmap(NULL, size, prot, MAP_SHARED, fd, 0);
    //关闭文件描述符
    close(fd);
    //测试,通过一个虚拟地址设置数据,两个虚拟地址得到相同的数据
    *add1 = 0xdeafbeef;
    printf("Address of add1 is: %p, value of add1 is: 0x%x\n", add1, *add1);
    printf("Address of add2 is: %p, value of add2 is: 0x%x\n", add2, *add2);
    return 0;
}

在Linux上通过gcc编译后运行文件,得到的结果如下:

注意

这里使用的系统调用shm_open()函数,需要在编译时加上-lrt,否则可能会出现链接错误。示例中调用mmap两次返回两个地址变量,从结果我们可以发现,两个变量对应两个不同的虚拟地址,分别是0x7f56f2989000和0x7f56f2988000,但是因为它们都是通过mmap映射同一个内存共享对象,所以它们的物理地址是一样的,并且它们的值都是0xdeafbeef。

2.Windows系统

Windows系统也提供地址映射函数,使用系统函数CreateFileMapping()创建内存映射对象,再多次调用MapViewOf File()把一个内存映射对象映射到多个虚拟地址上,然后再操作虚拟地址。整体实现和Linux非常类似,这里提供一个示例程序(代码可以从GitHub 下载),如下所示:


#include <Windows.h>
#include <WinBase.h>
int main()
{
    size_t size = sizeof(LPINT);
    HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE,
        NULL,
        PAGE_READWRITE,
        0, size,
        NULL);
    LPINT add1 = (LPINT)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, size);
    LPINT add2 = (LPINT)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, size);
    *add1 = 0xdeafbeef;
    printf("Address of add1 is: %p, value of add1 is: 0x%x\n", add1, *add1);
    printf("Address of add2 is: %p, value of add2 is: 0x%x\n", add2, *add2);
    UnmapViewOfFile(add1);
    UnmapViewOfFile(add2);
    CloseHandle(hMapFile);
    return 0;
}

这个例子非常简单,仅保留必要工作,省略了很多异常处理。笔者在Windows平台使用Visual Studio Community 2017 运行上述代码,可以得到如下结果:

这是与Linux中一样的结果。介绍完Linux和Windows平台如何实现运行的结果多视图映射,下面我们看一下ZGC是如何实现地址的多视图映射的。 3wiJHDoJHEZbbBBG2fe15LhK0FuFBAgggt0oZLjLbP7VzJBFuvuH1gadBzZS/Jo+

点击中间区域
呼出菜单
上一章
目录
下一章
×