一种通过linux特性mmap节约内存的思想

最近一个JNI调用的库,需要一口气要一个高达1GB占用的文件放入一个数组去进行数据处理,此时如果手机的内存不足的话很容易导致我们的APP在使用该功能时OOM,但是这个第三方库我没有源码改不了,所以想了一下自己学过的知识,突然想到以前学Linux C编程的时候,可以用mmap把外存文件映射为一个内存地址,这样就可以不实际占用内存的情况下读取这个文件了,于是写了一个demo测试一下:

#include "stdio.h"
#include "stdlib.h"
#include<sys/mman.h>
#include<unistd.h>
#include<fcntl.h>

int main() {
    int f = open("/media/chenjiezhu/doc/迅雷下载/cn_windows_server_2012_r2_with_update_x64_dvd_6052725.iso", O_RDWR);
    long fileSize = 5545705472;
    //获得磁盘文件的内存映射
    char *mapped = (char *) mmap(0 , fileSize, PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);
    long i;
    for(long i = fileSize - 10000; i < fileSize; i++) {
        printf("%d", *(mapped + i));
    }
    return 0;
}

我加载了一个windows_server的镜像作为大文件读写测试,看看内存占用:

 PID  USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND   
 7399 chenjie+  20   0 5419912   8808   8716 S  22.8  0.0   0:01.48 test1.bin  

 

按照物理内存占用公式RES - SHR = 8808 - 8716 = 92byte,实际占用内存才这么点,但可以实现和加载了整个大文件在内存里面使用的效果,那我们使用那个第三方库时,完全可以把数组数据怼进文件里面,再mmap出一个地址,让第三方库直接使用这个地址去取数据即可缓解内存压力。

 

封装一下,再依赖一些指针的奇技淫巧,还可以把映射出来的指针当二维数组读写

/**@author 陈杰柱**/

#include "stdio.h"
#include "stdlib.h"
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

typedef struct fileMapItem {
    int fileHandle;
    void* fileMapAddress;  
    long fileSize;
} FileMapItem;
FileMapItem getFileMapAddress(char* filePath);
void endFileMap(FileMapItem fileMapItem);

int main() {
    FileMapItem f = getFileMapAddress("./testReadFile.txt");
    int i, j;
    char **p = malloc(2 * sizeof(char*));
    *p = (char*) f.fileMapAddress;
    *(p + 1) = (char*) (f.fileMapAddress + 3);
    for(i = 0; i < 2; i++) {
        for(j = 0; j < 3; j++) {
            printf("i = %d, j = %d, c = %c\n", i, j, p[i][j]);
        }    
    }
    endFileMap(f);
    free(p);
    return 0;
}

/*Map a file to memory to relieve memory pressure.
It won't be loading files into memory, 
just make it look like it's in memory and operate like it's in memory*/
FileMapItem getFileMapAddress(char* filePath) {
    struct stat buf;  
    FileMapItem fItem;
    //give file size
    if(stat(filePath, &buf) < 0) {  
        fItem.fileHandle = -1;
        fItem.fileMapAddress = (void*) -1;
        return fItem;  
    }  
    long fileSize = buf.st_size;  
    int f = open(filePath, O_RDWR);
    //map the file start position as a FAKE memory address.
    void* fileMapAddress = mmap(0 , fileSize, PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);
    fItem.fileSize = fileSize;
    fItem.fileHandle = f;
    fItem.fileMapAddress = fileMapAddress;
    return fItem;
}

/*close the file map */
void endFileMap(FileMapItem fileMapItem) {
    munmap(fileMapItem.fileMapAddress, fileMapItem.fileSize);
    close(fileMapItem.fileHandle);
}

文件内容就是0123456789,所以输出的结果是:

i = 0, j = 0, c = 0
i = 0, j = 1, c = 1
i = 0, j = 2, c = 2
i = 1, j = 0, c = 3
i = 1, j = 1, c = 4
i = 1, j = 2, c = 5

证明二维化正确

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值