天天看點

虛拟記憶體配置設定 和 mmap

虛拟記憶體配置設定

#include <iostream>
#include <cstdio>
//#include <cmalloc>
using namespace std;
const int block_size=1024*1024*10;
char* address[1024];
int main(){
    int total_heap=0;
    int i=0;
    printf("main function address:%p\n", main);
    printf("printf function address:%p\n", printf);
    printf("static mem address:%p\n",address);
    printf("press enter to alloc heap\n");
    while(1){
        getchar();
        address[i]=new char[block_size];
        printf("alloc heap %p, total: %d M\n",address[i],i);
        printf("%d\n",*((int*)address[i]-1));
        printf("%d\n",*((int*)address[i]-2));
        i++;
    }
    return 0;
}
           

這裡可以把輸出和

cat /proc/{pid}/maps

的輸出中的位址做對比

>>> 1052674-1024*1024
4098
           
main function address:0x4007ed
printf function address:0x400670
static mem address:0x6010a0
press enter to alloc heap

alloc heap 0x7f0a08945010, total: 1 M
0
1052674

alloc heap 0x7f0a07b49010, total: 2 M
0
1052674

alloc heap 0x7f0a07a48010, total: 3 M
0
1052674
           

還有就是每塊新配置設定的位址前面的這個表示長度的東西總是比代碼中定義的block_size 多4098,不知道為啥?

剛好是一個塊的大小,存儲malloc的位址的結構體的其他部分

mmap

// use mmap
#include <iostream>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include "file_data.h"

using namespace std;

static char buff[1024];
int main(){
    int fd=open(data_file, O_RDWR,0666);
    if(fd<0){
        perror("can not open file");
        exit(-1);
    }
    char *p=(char*)mmap(NULL,map_size, PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//    for(int i=0;i<map_size;i++){
//        p[i]=2;
//    }

    for(int i=0;i<map_size/1024;i++){
        memcpy(p+1024*i,buff,1024);
    }
    
    int rc=munmap(p,file_size);
    if(rc<0){
        perror("munmap");
    }
    close(fd);
    return 0;
}
           
// use write 
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include "file_data.h"
#include "util.h"
#include <cassert>
using namespace std;


char buff[1024];


int main(){
    int fd=open(data_file,O_WRONLY);
    check_rc(fd,"can not open file");
    lseek(fd, 0, SEEK_SET);

    int total=0;
    while(total< map_size) {
        int l=write(fd, buff, 1024);
        check_rc(l,"write");
        total+=l;
    }
    return 0;
}
           

從下面的輸出看,mmap 的耗時約為 write 的1/4

$ time ./file_mmap 

real	0m0.554s
user	0m0.314s
sys	0m0.234s

$ time ./file_write 

real	0m1.733s
user	0m0.410s
sys	0m1.120s
           

幾個注意地方:

  • 匿名映射 fd 傳 -1
  • 如果mmap 中的那個映射長度是可以大于/小于檔案長度的,但是實際寫入時,超過mmap定義的size 或者 超過檔案的長度都會報錯
  • open 時,檔案要有讀寫的權限,隻有寫權限會報錯,不知道為啥,按理說應該權限比對就可以,但是open 和 mmap 都改成隻有寫權限會報錯
  • mmap 後關閉檔案,寫入依然有效

程式kill 的 檔案寫入測試

// write file
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <fcntl.h>
#include <sys/mman.h>
#include "util.h"
#include "file_data.h"
#include <ctime>
#include <unistd.h>
using namespace std;

int main() {
    int fd = open(file_name, O_RDWR);
    check_rc(fd,"can not open file");
    srand((unsigned  int)time(NULL));
    char *p = (char*)mmap(NULL, file_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    if( (long long)p==-1){
        perror("mmap error");
    }
    for(int i=0;i<file_size;i++){
        int r=rand()%256;
        p[i]= (char)r;
        printf("write to %d:%d\n",i,r);
    }
    return 0;
}
           
//read file
#include<iostream>
#include <fcntl.h>
#include <unistd.h>
#include "file_data.h"

using namespace std;


int main(int argc, char ** argv){
    unsigned char buff[1024];
    int fp=open(file_name,O_RDONLY);
    if(fp<0){
        perror("can not open file");
        exit(-1);
    }
    int offset;
    if(argc==1){
        offset=0;
    }else{
        offset=atoi(argv[1]);
    }
    lseek(fp,offset,SEEK_SET);
    read(fp,buff,1);
    close(fp);
    unsigned x=buff[0];
    printf("read from offset %d:%u\n",offset,(buff[0]));
    return 0;
}
           

參考:

https://www.jianshu.com/p/eece39beee20

https://en.wikipedia.org/wiki/Mmap

https://www.cnblogs.com/huxiao-tee/p/4660352.html (不是很好了解,不過極端情況講得比較好)

繼續閱讀